diff --git a/apier/v1/cdre.go b/apier/v1/cdre.go
index c2bb3eb17..990bd8b30 100644
--- a/apier/v1/cdre.go
+++ b/apier/v1/cdre.go
@@ -34,7 +34,6 @@ import (
"unicode/utf8"
"github.com/cgrates/cgrates/cdre"
- "github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
@@ -93,28 +92,11 @@ func (self *ApierV1) ExportCdrsToZipString(attr utils.AttrExpFileCdrs, reply *st
// Export Cdrs to file
func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.ExportedFileCdrs) error {
var err error
- exportTemplate := self.Config.CdreDefaultInstance
- if attr.ExportTemplate != nil && len(*attr.ExportTemplate) != 0 { // XML Template defined, can be field names or xml reference
- if strings.HasPrefix(*attr.ExportTemplate, utils.XML_PROFILE_PREFIX) {
- if self.Config.XmlCfgDocument == nil {
- return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, "XmlDocumentNotLoaded")
- }
- expTplStr := *attr.ExportTemplate
- if xmlTemplates := self.Config.XmlCfgDocument.GetCdreCfgs(expTplStr[len(utils.XML_PROFILE_PREFIX):]); xmlTemplates == nil {
- return fmt.Errorf("%s:ExportTemplate", utils.ERR_NOT_FOUND)
- } else {
- if exportTemplate, err = config.NewCdreConfigFromXmlCdreCfg(xmlTemplates[expTplStr[len(utils.XML_PROFILE_PREFIX):]]); err != nil {
- return fmt.Errorf("%s:ExportTemplate:%s", utils.ERR_SERVER_ERROR, err.Error())
- }
- }
- } else {
- exportTemplate = config.NewDefaultCdreConfig()
- if contentFlds, err := config.NewCfgCdrFieldsFromIds(exportTemplate.CdrFormat == utils.CDRE_FIXED_WIDTH,
- strings.Split(*attr.ExportTemplate, string(utils.CSV_SEP))...); err != nil {
- return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
- } else {
- exportTemplate.ContentFields = contentFlds
- }
+ exportTemplate := self.Config.CdreProfiles[utils.META_DEFAULT]
+ if attr.ExportTemplate != nil && len(*attr.ExportTemplate) != 0 { // Export template prefered, use it
+ var hasIt bool
+ if exportTemplate, hasIt = self.Config.CdreProfiles[*attr.ExportTemplate]; !hasIt {
+ return fmt.Errorf("%s:ExportTemplate", utils.ERR_NOT_FOUND)
}
}
if exportTemplate == nil {
diff --git a/apier/v1/derivedcharging.go b/apier/v1/derivedcharging.go
index f54d80400..25dfb7a81 100644
--- a/apier/v1/derivedcharging.go
+++ b/apier/v1/derivedcharging.go
@@ -29,7 +29,7 @@ func (self *ApierV1) GetDerivedChargers(attrs utils.AttrDerivedChargers, reply *
if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Direction", "Account", "Subject"}); len(missing) != 0 {
return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing)
}
- if hDc, err := engine.HandleGetDerivedChargers(self.AccountDb, self.Config, attrs); err != nil {
+ if hDc, err := engine.HandleGetDerivedChargers(self.AccountDb, attrs); err != nil {
return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error())
} else if hDc != nil {
*reply = hDc
diff --git a/cdrc/cdrc.go b/cdrc/cdrc.go
index cd0eb162b..5c16dd8a8 100644
--- a/cdrc/cdrc.go
+++ b/cdrc/cdrc.go
@@ -29,7 +29,6 @@ import (
"path"
"strconv"
"time"
- "unicode/utf8"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
@@ -83,12 +82,8 @@ func populateStoredCdrField(cdr *utils.StoredCdr, fieldId, fieldVal string) erro
}
func NewCdrc(cdrcCfg *config.CdrcConfig, httpSkipTlsCheck bool, cdrServer *engine.CDRS) (*Cdrc, error) {
- if len(cdrcCfg.FieldSeparator) != 1 {
- return nil, fmt.Errorf("Unsupported csv separator: %s", cdrcCfg.FieldSeparator)
- }
- csvSepRune, _ := utf8.DecodeRune([]byte(cdrcCfg.FieldSeparator))
cdrc := &Cdrc{cdrsAddress: cdrcCfg.CdrsAddress, CdrFormat: cdrcCfg.CdrFormat, cdrInDir: cdrcCfg.CdrInDir, cdrOutDir: cdrcCfg.CdrOutDir,
- cdrSourceId: cdrcCfg.CdrSourceId, runDelay: cdrcCfg.RunDelay, csvSep: csvSepRune, duMultiplyFactor: cdrcCfg.DataUsageMultiplyFactor, cdrFields: cdrcCfg.CdrFields, httpSkipTlsCheck: httpSkipTlsCheck, cdrServer: cdrServer}
+ cdrSourceId: cdrcCfg.CdrSourceId, runDelay: cdrcCfg.RunDelay, csvSep: cdrcCfg.FieldSeparator, duMultiplyFactor: cdrcCfg.DataUsageMultiplyFactor, cdrFields: cdrcCfg.CdrFields, httpSkipTlsCheck: httpSkipTlsCheck, cdrServer: cdrServer}
// Before processing, make sure in and out folders exist
for _, dir := range []string{cdrc.cdrInDir, cdrc.cdrOutDir} {
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
diff --git a/cdrc/cdrc_local_test.go b/cdrc/cdrc_local_test.go
index 39ab0ad0a..a9eba223f 100644
--- a/cdrc/cdrc_local_test.go
+++ b/cdrc/cdrc_local_test.go
@@ -96,10 +96,10 @@ func TestLoadConfigt(*testing.T) {
if !*testLocal {
return
}
- cfgPath = path.Join(*dataDir, "conf", "samples", "apier_local_test.cfg")
- cfg, _ = config.NewCGRConfigFromFile(&cfgPath)
- if len(cfg.CdrcInstances) > 0 {
- cdrcCfg = cfg.CdrcInstances[0]
+ cfgPath = path.Join(*dataDir, "conf", "samples", "apier")
+ cfg, _ = config.NewCGRConfigFromFolder(cfgPath)
+ if len(cfg.CdrcProfiles) > 0 {
+ cdrcCfg = cfg.CdrcProfiles[utils.META_DEFAULT]
}
}
diff --git a/cdrc/cdrc_test.go b/cdrc/cdrc_test.go
index 2b9b7e108..c9db55b69 100644
--- a/cdrc/cdrc_test.go
+++ b/cdrc/cdrc_test.go
@@ -29,7 +29,7 @@ import (
func TestRecordForkCdr(t *testing.T) {
cgrConfig, _ := config.NewDefaultCGRConfig()
- cdrcConfig := cgrConfig.CdrcInstances[0]
+ cdrcConfig := cgrConfig.CdrcProfiles[utils.META_DEFAULT]
cdrcConfig.CdrFields = append(cdrcConfig.CdrFields, &config.CfgCdrField{Tag: "SupplierTest", Type: utils.CDRFIELD, CdrFieldId: "supplier", Value: []*utils.RSRField{&utils.RSRField{Id: "14"}}})
cdrc := &Cdrc{CdrFormat: CSV, cdrSourceId: "TEST_CDRC", cdrFields: cdrcConfig.CdrFields}
cdrRow := []string{"firstField", "secondField"}
diff --git a/cdre/cdrexporter_test.go b/cdre/cdrexporter_test.go
index b147f312c..9c274bfb4 100644
--- a/cdre/cdrexporter_test.go
+++ b/cdre/cdrexporter_test.go
@@ -51,14 +51,14 @@ func TestCdreGetCombimedCdrFieldVal(t *testing.T) {
Category: "call", Account: "1000", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(),
Usage: time.Duration(10) * time.Second, MediationRunId: "RETAIL1", Cost: 5.01},
}
- cdre, err := NewCdrExporter(cdrs, logDb, cfg.CdreDefaultInstance, cfg.CdreDefaultInstance.CdrFormat, cfg.CdreDefaultInstance.FieldSeparator,
+ cdre, err := NewCdrExporter(cdrs, logDb, cfg.CdreProfiles["*default"], cfg.CdreProfiles["*default"].CdrFormat, cfg.CdreProfiles["*default"].FieldSeparator,
"firstexport", 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify)
if err != nil {
t.Error("Unexpected error received: ", err)
}
fltrRule, _ := utils.ParseRSRFields("~mediation_runid:s/default/RUN_RTL/", utils.INFIELD_SEP)
val, _ := utils.ParseRSRFields("cost", utils.INFIELD_SEP)
- cfgCdrFld, _ := config.NewCfgCdrFieldWithDefaults(false, val, fltrRule, nil, nil, nil, nil, nil, nil, nil, nil)
+ cfgCdrFld := &config.CfgCdrField{Tag: "cost", Type: "cdrfield", CdrFieldId: "cost", Value: val, Filter: fltrRule}
if costVal, err := cdre.getCombimedCdrFieldVal(cdrs[3], cfgCdrFld); err != nil {
t.Error(err)
} else if costVal != "1.01" {
@@ -66,7 +66,7 @@ func TestCdreGetCombimedCdrFieldVal(t *testing.T) {
}
fltrRule, _ = utils.ParseRSRFields("~mediation_runid:s/default/RETAIL1/", utils.INFIELD_SEP)
val, _ = utils.ParseRSRFields("account", utils.INFIELD_SEP)
- cfgCdrFld, _ = config.NewCfgCdrFieldWithDefaults(false, val, fltrRule, nil, nil, nil, nil, nil, nil, nil, nil)
+ cfgCdrFld = &config.CfgCdrField{Tag: "account", Type: "cdrfield", CdrFieldId: "account", Value: val, Filter: fltrRule}
if acntVal, err := cdre.getCombimedCdrFieldVal(cdrs[3], cfgCdrFld); err != nil {
t.Error(err)
} else if acntVal != "1000" {
@@ -83,7 +83,7 @@ func TestGetDateTimeFieldVal(t *testing.T) {
ExtraFields: map[string]string{"stop_time": "2014-06-11 19:19:00 +0000 UTC", "fieldextr2": "valextr2"}}
val, _ := utils.ParseRSRFields("stop_time", utils.INFIELD_SEP)
layout := "2006-01-02 15:04:05"
- cfgCdrFld, _ := config.NewCfgCdrFieldWithDefaults(false, val, nil, nil, nil, nil, nil, &layout, nil, nil, nil)
+ cfgCdrFld := &config.CfgCdrField{Tag: "stop_time", Type: "cdrfield", CdrFieldId: "stop_time", Value: val, Layout: layout}
if cdrVal, err := cdreTst.getDateTimeFieldVal(cdrTst, cfgCdrFld); err != nil {
t.Error(err)
} else if cdrVal != "2014-06-11 19:19:00" {
@@ -91,12 +91,12 @@ func TestGetDateTimeFieldVal(t *testing.T) {
}
// Test filter
fltr, _ := utils.ParseRSRFields("~tenant:s/(.+)/itsyscom.com/", utils.INFIELD_SEP)
- cfgCdrFld, _ = config.NewCfgCdrFieldWithDefaults(false, val, fltr, nil, nil, nil, nil, &layout, nil, nil, nil)
+ cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: "cdrfield", CdrFieldId: "stop_time", Value: val, Filter: fltr, Layout: layout}
if _, err := cdreTst.getDateTimeFieldVal(cdrTst, cfgCdrFld); err == nil {
t.Error(err)
}
val, _ = utils.ParseRSRFields("fieldextr2", utils.INFIELD_SEP)
- cfgCdrFld, _ = config.NewCfgCdrFieldWithDefaults(false, val, nil, nil, nil, nil, nil, &layout, nil, nil, nil)
+ cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: "cdrfield", CdrFieldId: "stop_time", Value: val, Layout: layout}
// Test time parse error
if _, err := cdreTst.getDateTimeFieldVal(cdrTst, cfgCdrFld); err == nil {
t.Error("Should give error here, got none.")
@@ -110,14 +110,14 @@ func TestCdreCdrFieldValue(t *testing.T) {
Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(),
Usage: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 1.01}
val, _ := utils.ParseRSRFields("destination", utils.INFIELD_SEP)
- cfgCdrFld, _ := config.NewCfgCdrFieldWithDefaults(false, val, nil, nil, nil, nil, nil, nil, nil, nil, nil)
+ cfgCdrFld := &config.CfgCdrField{Tag: "destination", Type: "cdrfield", CdrFieldId: "destination", Value: val}
if val, err := cdre.cdrFieldValue(cdr, cfgCdrFld); err != nil {
t.Error(err)
} else if val != cdr.Destination {
t.Errorf("Expecting: %s, received: %s", cdr.Destination, val)
}
fltr, _ := utils.ParseRSRFields("~tenant:s/(.+)/itsyscom.com/", utils.INFIELD_SEP)
- cfgCdrFld, _ = config.NewCfgCdrFieldWithDefaults(false, val, fltr, nil, nil, nil, nil, nil, nil, nil, nil)
+ cfgCdrFld = &config.CfgCdrField{Tag: "destination", Type: "cdrfield", CdrFieldId: "destination", Value: val, Filter: fltr}
if _, err := cdre.cdrFieldValue(cdr, cfgCdrFld); err == nil {
t.Error("Failed to use filter")
}
diff --git a/cdre/csv_test.go b/cdre/csv_test.go
index 14c4732f8..e5e78cb72 100644
--- a/cdre/csv_test.go
+++ b/cdre/csv_test.go
@@ -39,7 +39,8 @@ func TestCsvCdrWriter(t *testing.T) {
Usage: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID,
ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, Cost: 1.01,
}
- cdre, err := NewCdrExporter([]*utils.StoredCdr{storedCdr1}, logDb, cfg.CdreDefaultInstance, utils.CSV, ',', "firstexport", 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify)
+ cdre, err := NewCdrExporter([]*utils.StoredCdr{storedCdr1}, logDb, cfg.CdreProfiles["*default"], utils.CSV, ',', "firstexport", 0.0, 0.0, 0, 4,
+ cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify)
if err != nil {
t.Error("Unexpected error received: ", err)
}
@@ -67,7 +68,7 @@ func TestAlternativeFieldSeparator(t *testing.T) {
Usage: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID,
ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, Cost: 1.01,
}
- cdre, err := NewCdrExporter([]*utils.StoredCdr{storedCdr1}, logDb, cfg.CdreDefaultInstance, utils.CSV, '|', "firstexport", 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify)
+ cdre, err := NewCdrExporter([]*utils.StoredCdr{storedCdr1}, logDb, cfg.CdreProfiles["*default"], utils.CSV, '|', "firstexport", 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify)
if err != nil {
t.Error("Unexpected error received: ", err)
}
diff --git a/cdre/fixedwidth_test.go b/cdre/fixedwidth_test.go
index 91fc8f29a..6f661137b 100644
--- a/cdre/fixedwidth_test.go
+++ b/cdre/fixedwidth_test.go
@@ -29,65 +29,95 @@ import (
"github.com/cgrates/cgrates/utils"
)
-var hdrCfgFlds = []*config.XmlCfgCdrField{
- &config.XmlCfgCdrField{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("10"), Width: utils.IntPointer(2)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Filler1"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(3)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("DistributorCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("VOI"), Width: utils.IntPointer(3)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("FileSeqNr"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer("export_id"), Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("zeroleft")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("LastCdr"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_LASTCDRATIME), Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("FileCreationfTime"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer("time_now"), Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("FileVersion"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("01"), Width: utils.IntPointer(2)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Filler2"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(105)},
+var hdrJsnCfgFlds = []*config.CdrFieldJsonCfg{
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^10"), Width: utils.IntPointer(2)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler1"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(3)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("DistributorCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^VOI"), Width: utils.IntPointer(3)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileSeqNr"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer("export_id"),
+ Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("zeroleft")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("LastCdr"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_LASTCDRATIME),
+ Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileCreationfTime"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer("time_now"),
+ Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileVersion"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^01"), Width: utils.IntPointer(2)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler2"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(105)},
}
-var contentCfgFlds = []*config.XmlCfgCdrField{
- &config.XmlCfgCdrField{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("20"), Width: utils.IntPointer(2)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Account"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.ACCOUNT), Width: utils.IntPointer(12), Strip: utils.StringPointer("left"), Padding: utils.StringPointer("right")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Subject"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.SUBJECT), Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("CLI"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer("cli"), Width: utils.IntPointer(15), Strip: utils.StringPointer("xright"), Padding: utils.StringPointer("right")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Destination"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.DESTINATION), Width: utils.IntPointer(24), Strip: utils.StringPointer("xright"), Padding: utils.StringPointer("right")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("TOR"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("02"), Width: utils.IntPointer(2)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("SubtypeTOR"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("11"), Width: utils.IntPointer(4), Padding: utils.StringPointer("right")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("SetupTime"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.SETUP_TIME), Width: utils.IntPointer(12), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right"),
- Layout: utils.StringPointer("020106150400")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Duration"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.USAGE), Width: utils.IntPointer(6), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right"),
- Layout: utils.StringPointer(utils.SECONDS)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("DataVolume"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(6)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("TaxCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("1"), Width: utils.IntPointer(1)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("OperatorCode"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer("opercode"), Width: utils.IntPointer(2), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("ProductId"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer("productid"), Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("NetworkId"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("3"), Width: utils.IntPointer(1)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("CallId"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.ACCID), Width: utils.IntPointer(16), Padding: utils.StringPointer("right")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Filler"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(8)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Filler"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(8)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("TerminationCode"), Type: utils.StringPointer(CONCATENATED_CDRFIELD), Value: utils.StringPointer("operator,product"), Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Cost"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.COST), Width: utils.IntPointer(9), Padding: utils.StringPointer("zeroleft")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("DestinationPrivacy"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_MASKDESTINATION), Width: utils.IntPointer(1)},
+var contentJsnCfgFlds = []*config.CdrFieldJsonCfg{
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^20"), Width: utils.IntPointer(2)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Account"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.ACCOUNT), Width: utils.IntPointer(12),
+ Strip: utils.StringPointer("left"), Padding: utils.StringPointer("right")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.SUBJECT), Width: utils.IntPointer(5),
+ Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("CLI"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer("cli"), Width: utils.IntPointer(15),
+ Strip: utils.StringPointer("xright"), Padding: utils.StringPointer("right")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.DESTINATION), Width: utils.IntPointer(24),
+ Strip: utils.StringPointer("xright"), Padding: utils.StringPointer("right")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TOR"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^02"), Width: utils.IntPointer(2)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("SubtypeTOR"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^11"), Width: utils.IntPointer(4),
+ Padding: utils.StringPointer("right")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.SETUP_TIME), Width: utils.IntPointer(12),
+ Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right"), Layout: utils.StringPointer("020106150400")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Duration"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.USAGE), Width: utils.IntPointer(6),
+ Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right"), Layout: utils.StringPointer(utils.SECONDS)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("DataVolume"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(6)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TaxCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^1"), Width: utils.IntPointer(1)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("OperatorCode"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer("opercode"), Width: utils.IntPointer(2),
+ Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("ProductId"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer("productid"), Width: utils.IntPointer(5),
+ Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("NetworkId"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^3"), Width: utils.IntPointer(1)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("CallId"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.ACCID), Width: utils.IntPointer(16),
+ Padding: utils.StringPointer("right")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(8)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(8)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TerminationCode"), Type: utils.StringPointer(CONCATENATED_CDRFIELD), Value: utils.StringPointer("operator,product"),
+ Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("right")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Cost"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer(utils.COST), Width: utils.IntPointer(9),
+ Padding: utils.StringPointer("zeroleft")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("DestinationPrivacy"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_MASKDESTINATION),
+ Width: utils.IntPointer(1)},
}
-var trailerCfgFlds = []*config.XmlCfgCdrField{
- &config.XmlCfgCdrField{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("90"), Width: utils.IntPointer(2)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Filler1"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(3)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("DistributorCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("VOI"), Width: utils.IntPointer(3)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("FileSeqNr"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_EXPORTID), Width: utils.IntPointer(5), Strip: utils.StringPointer("right"), Padding: utils.StringPointer("zeroleft")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("NumberOfRecords"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_NRCDRS), Width: utils.IntPointer(6), Padding: utils.StringPointer("zeroleft")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("CdrsDuration"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_DURCDRS), Width: utils.IntPointer(8), Padding: utils.StringPointer("zeroleft"), Layout: utils.StringPointer(utils.SECONDS)},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("FirstCdrTime"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_FIRSTCDRATIME), Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("LastCdrTime"), Type: utils.StringPointer(utils.METATAG), Value: utils.StringPointer(META_LASTCDRATIME), Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
- &config.XmlCfgCdrField{Tag: utils.StringPointer("Filler2"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(93)},
+var trailerJsnCfgFlds = []*config.CdrFieldJsonCfg{
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("TypeOfRecord"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^90"), Width: utils.IntPointer(2)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler1"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(3)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("DistributorCode"), Type: utils.StringPointer(utils.CONSTANT), Value: utils.StringPointer("^VOI"), Width: utils.IntPointer(3)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FileSeqNr"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_EXPORTID), Width: utils.IntPointer(5),
+ Strip: utils.StringPointer("right"), Padding: utils.StringPointer("zeroleft")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("NumberOfRecords"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_NRCDRS),
+ Width: utils.IntPointer(6), Padding: utils.StringPointer("zeroleft")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("CdrsDuration"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_DURCDRS),
+ Width: utils.IntPointer(8), Padding: utils.StringPointer("zeroleft"), Layout: utils.StringPointer(utils.SECONDS)},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("FirstCdrTime"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_FIRSTCDRATIME),
+ Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("LastCdrTime"), Type: utils.StringPointer(utils.METATAG), Cdr_field_id: utils.StringPointer(META_LASTCDRATIME),
+ Width: utils.IntPointer(12), Layout: utils.StringPointer("020106150400")},
+ &config.CdrFieldJsonCfg{Tag: utils.StringPointer("Filler2"), Type: utils.StringPointer(utils.FILLER), Width: utils.IntPointer(93)},
}
+var hdrCfgFlds, contentCfgFlds, trailerCfgFlds []*config.CfgCdrField
+
// Write one CDR and test it's results only for content buffer
func TestWriteCdr(t *testing.T) {
+ var err error
wrBuf := &bytes.Buffer{}
logDb, _ := engine.NewMapStorage()
cfg, _ := config.NewDefaultCGRConfig()
- fixedWidth := utils.CDRE_FIXED_WIDTH
- exportTpl := &config.CgrXmlCdreCfg{
- CdrFormat: &fixedWidth,
- Header: &config.CgrXmlCfgCdrHeader{Fields: hdrCfgFlds},
- Content: &config.CgrXmlCfgCdrContent{Fields: contentCfgFlds},
- Trailer: &config.CgrXmlCfgCdrTrailer{Fields: trailerCfgFlds},
+ if hdrCfgFlds, err = config.CfgCdrFieldsFromCdrFieldsJsonCfg(hdrJsnCfgFlds); err != nil {
+ t.Error(err)
+ }
+ if contentCfgFlds, err = config.CfgCdrFieldsFromCdrFieldsJsonCfg(contentJsnCfgFlds); err != nil {
+ t.Error(err)
+ }
+ if trailerCfgFlds, err = config.CfgCdrFieldsFromCdrFieldsJsonCfg(trailerJsnCfgFlds); err != nil {
+ t.Error(err)
+ }
+ cdreCfg := &config.CdreConfig{
+ CdrFormat: utils.CDRE_FIXED_WIDTH,
+ HeaderFields: hdrCfgFlds,
+ ContentFields: contentCfgFlds,
+ TrailerFields: trailerCfgFlds,
}
cdr := &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()),
TOR: utils.VOICE, OrderId: 1, AccId: "dsafdsaf", CdrHost: "192.168.1.1",
@@ -98,17 +128,13 @@ func TestWriteCdr(t *testing.T) {
Usage: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 2.34567,
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"},
}
- cdreCfg, err := config.NewCdreConfigFromXmlCdreCfg(exportTpl)
- if err != nil {
- t.Error(err)
- }
cdre, err := NewCdrExporter([]*utils.StoredCdr{cdr}, logDb, cdreCfg, utils.CDRE_FIXED_WIDTH, ',', "fwv_1", 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", -1, cfg.HttpSkipTlsVerify)
if err != nil {
t.Error(err)
}
- eHeader := "10 VOI0000007111308420024031415390001 \n"
+ eHeader := "10 VOIfwv_107111308420018011511340001 \n"
eContentOut := "201001 1001 1002 0211 07111308420010 1 3dsafdsaf 0002.34570\n"
- eTrailer := "90 VOI0000000000100000010071113084260071113084200 \n"
+ eTrailer := "90 VOIfwv_100000100000010071113084200071113084200 \n"
if err := cdre.writeOut(wrBuf); err != nil {
t.Error(err)
}
@@ -145,12 +171,11 @@ func TestWriteCdr(t *testing.T) {
func TestWriteCdrs(t *testing.T) {
wrBuf := &bytes.Buffer{}
logDb, _ := engine.NewMapStorage()
- fixedWidth := utils.CDRE_FIXED_WIDTH
- exportTpl := &config.CgrXmlCdreCfg{
- CdrFormat: &fixedWidth,
- Header: &config.CgrXmlCfgCdrHeader{Fields: hdrCfgFlds},
- Content: &config.CgrXmlCfgCdrContent{Fields: contentCfgFlds},
- Trailer: &config.CgrXmlCfgCdrTrailer{Fields: trailerCfgFlds},
+ cdreCfg := &config.CdreConfig{
+ CdrFormat: utils.CDRE_FIXED_WIDTH,
+ HeaderFields: hdrCfgFlds,
+ ContentFields: contentCfgFlds,
+ TrailerFields: trailerCfgFlds,
}
cdr1 := &utils.StoredCdr{CgrId: utils.Sha1("aaa1", time.Date(2013, 11, 7, 8, 42, 20, 0, time.UTC).String()),
TOR: utils.VOICE, OrderId: 2, AccId: "aaa1", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org",
@@ -178,10 +203,6 @@ func TestWriteCdrs(t *testing.T) {
ExtraFields: map[string]string{"productnumber": "12344", "fieldextr2": "valextr2"},
}
cfg, _ := config.NewDefaultCGRConfig()
- cdreCfg, err := config.NewCdreConfigFromXmlCdreCfg(exportTpl)
- if err != nil {
- t.Error(err)
- }
cdre, err := NewCdrExporter([]*utils.StoredCdr{cdr1, cdr2, cdr3, cdr4}, logDb, cdreCfg, utils.CDRE_FIXED_WIDTH, ',',
"fwv_1", 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", -1, cfg.HttpSkipTlsVerify)
if err != nil {
diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go
index 0fb3954ce..51e56a156 100644
--- a/cmd/cgr-engine/cgr-engine.go
+++ b/cmd/cgr-engine/cgr-engine.go
@@ -55,7 +55,7 @@ const (
)
var (
- cfgPath = flag.String("config", "/etc/cgrates/cgrates.cfg", "Configuration file location.")
+ cfgDir = flag.String("config_dir", "/etc/cgrates", "Configuration directory path.")
version = flag.Bool("version", false, "Prints the application version.")
raterEnabled = flag.Bool("rater", false, "Enforce starting of the rater daemon overwriting config")
schedEnabled = flag.Bool("scheduler", false, "Enforce starting of the scheduler daemon .overwriting config")
@@ -325,7 +325,7 @@ func main() {
}
// runtime.GOMAXPROCS(runtime.NumCPU()) // For now it slows down computing due to CPU management, to be reviewed in future Go releases
- cfg, err = config.NewCGRConfigFromFile(cfgPath)
+ cfg, err = config.NewCGRConfigFromFolder(*cfgDir)
if err != nil {
engine.Logger.Crit(fmt.Sprintf("Could not parse config: %s exiting!", err))
return
@@ -502,7 +502,7 @@ func main() {
go shutdownSessionmanagerSingnalHandler()
}
var cdrcEnabled bool
- for _, cdrcConfig := range cfg.CdrcInstances {
+ for _, cdrcConfig := range cfg.CdrcProfiles {
if cdrcConfig.Enabled == false {
continue // Ignore not enabled
} else if !cdrcEnabled {
diff --git a/config/cdrcconfig.go b/config/cdrcconfig.go
index bec3d904a..829834144 100644
--- a/config/cdrcconfig.go
+++ b/config/cdrcconfig.go
@@ -19,186 +19,14 @@ along with this program. If not, see
package config
import (
- "code.google.com/p/goconf/conf"
- "fmt"
- "github.com/cgrates/cgrates/utils"
- "strings"
"time"
)
-func NewCdrcConfigFromCgrXmlCdrcCfg(id string, xmlCdrcCfg *CgrXmlCdrcCfg) (*CdrcConfig, error) {
- cdrcCfg := NewDefaultCdrcConfig()
- cdrcCfg.Id = id
- if xmlCdrcCfg.Enabled != nil {
- cdrcCfg.Enabled = *xmlCdrcCfg.Enabled
- }
- if xmlCdrcCfg.CdrsAddress != nil {
- cdrcCfg.CdrsAddress = *xmlCdrcCfg.CdrsAddress
- }
- if xmlCdrcCfg.CdrFormat != nil {
- cdrcCfg.CdrFormat = *xmlCdrcCfg.CdrFormat
- }
- if xmlCdrcCfg.FieldSeparator != nil {
- cdrcCfg.FieldSeparator = *xmlCdrcCfg.FieldSeparator
- }
- if xmlCdrcCfg.DataUsageMultiplyFactor != nil {
- cdrcCfg.DataUsageMultiplyFactor = *xmlCdrcCfg.DataUsageMultiplyFactor
- }
- if xmlCdrcCfg.RunDelay != nil {
- cdrcCfg.RunDelay = time.Duration(*xmlCdrcCfg.RunDelay) * time.Second
- }
- if xmlCdrcCfg.CdrInDir != nil {
- cdrcCfg.CdrInDir = *xmlCdrcCfg.CdrInDir
- }
- if xmlCdrcCfg.CdrOutDir != nil {
- cdrcCfg.CdrOutDir = *xmlCdrcCfg.CdrOutDir
- }
- if xmlCdrcCfg.CdrSourceId != nil {
- cdrcCfg.CdrSourceId = *xmlCdrcCfg.CdrSourceId
- }
- if len(xmlCdrcCfg.CdrFields) != 0 {
- cdrcCfg.CdrFields = nil // Reinit the fields, so we do not inherit from defaults here
- }
- for _, xmlCdrField := range xmlCdrcCfg.CdrFields {
- if cdrFld, err := NewCfgCdrFieldFromCgrXmlCfgCdrField(xmlCdrField, cdrcCfg.CdrFormat == utils.CDRE_FIXED_WIDTH); err != nil {
- return nil, err
- } else {
- cdrcCfg.CdrFields = append(cdrcCfg.CdrFields, cdrFld)
- }
- }
- return cdrcCfg, nil
-}
-
-func NewDefaultCdrcConfig() *CdrcConfig {
- torTag, accIdTag, reqTypeTag, dirTag, tenantTag, categTag, acntTag, subjTag, dstTag, sTimeTag, aTimeTag, usageTag := utils.TOR,
- utils.ACCID, utils.REQTYPE, utils.DIRECTION, utils.TENANT, utils.CATEGORY, utils.ACCOUNT, utils.SUBJECT, utils.DESTINATION, utils.SETUP_TIME, utils.ANSWER_TIME, utils.USAGE
- torFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "2"}}, nil, nil, &torTag, nil, nil, nil, nil, nil, nil)
- accIdFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "3"}}, nil, nil, &accIdTag, nil, nil, nil, nil, nil, nil)
- reqTypeFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "4"}}, nil, nil, &reqTypeTag, nil, nil, nil, nil, nil, nil)
- directionFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "5"}}, nil, nil, &dirTag, nil, nil, nil, nil, nil, nil)
- tenantFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "6"}}, nil, nil, &tenantTag, nil, nil, nil, nil, nil, nil)
- categoryFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "7"}}, nil, nil, &categTag, nil, nil, nil, nil, nil, nil)
- acntFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "8"}}, nil, nil, &acntTag, nil, nil, nil, nil, nil, nil)
- subjFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "9"}}, nil, nil, &subjTag, nil, nil, nil, nil, nil, nil)
- dstFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "10"}}, nil, nil, &dstTag, nil, nil, nil, nil, nil, nil)
- setupTimeFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "11"}}, nil, nil, &sTimeTag, nil, nil, nil, nil, nil, nil)
- answerTimeFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "12"}}, nil, nil, &aTimeTag, nil, nil, nil, nil, nil, nil)
- usageFld, _ := NewCfgCdrFieldWithDefaults(false, []*utils.RSRField{&utils.RSRField{Id: "13"}}, nil, nil, &usageTag, nil, nil, nil, nil, nil, nil)
- cdrcCfg := &CdrcConfig{
- Id: utils.META_DEFAULT,
- Enabled: false,
- CdrsAddress: "",
- CdrFormat: utils.CSV,
- FieldSeparator: utils.FIELDS_SEP,
- DataUsageMultiplyFactor: 1.0,
- RunDelay: time.Duration(0),
- CdrInDir: "/var/log/cgrates/cdrc/in",
- CdrOutDir: "/var/log/cgrates/cdrc/out",
- CdrSourceId: utils.CSV,
- CdrFields: []*CfgCdrField{torFld, accIdFld, reqTypeFld, directionFld, tenantFld, categoryFld, acntFld, subjFld, dstFld, setupTimeFld, answerTimeFld, usageFld},
- }
- return cdrcCfg
-}
-
-func NewCdrcConfigFromFileParams(c *conf.ConfigFile) (*CdrcConfig, error) {
- var err error
- cdrcCfg := NewDefaultCdrcConfig()
- if hasOpt := c.HasOption("cdrc", "enabled"); hasOpt {
- cdrcCfg.Enabled, _ = c.GetBool("cdrc", "enabled")
- }
- if hasOpt := c.HasOption("cdrc", "cdrs"); hasOpt {
- cdrcCfg.CdrsAddress, _ = c.GetString("cdrc", "cdrs")
- }
- if hasOpt := c.HasOption("cdrc", "cdr_format"); hasOpt {
- cdrcCfg.CdrFormat, _ = c.GetString("cdrc", "cdr_format")
- }
- if hasOpt := c.HasOption("cdrc", "field_separator"); hasOpt {
- cdrcCfg.FieldSeparator, _ = c.GetString("cdrc", "field_separator")
- }
- if hasOpt := c.HasOption("cdrc", "data_usage_multiply_factor"); hasOpt {
- cdrcCfg.DataUsageMultiplyFactor, _ = c.GetFloat64("cdrc", "data_usage_multiply_factor")
- }
- if hasOpt := c.HasOption("cdrc", "run_delay"); hasOpt {
- durStr, _ := c.GetString("cdrc", "run_delay")
- if cdrcCfg.RunDelay, err = utils.ParseDurationWithSecs(durStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrc", "cdr_in_dir"); hasOpt {
- cdrcCfg.CdrInDir, _ = c.GetString("cdrc", "cdr_in_dir")
- }
- if hasOpt := c.HasOption("cdrc", "cdr_out_dir"); hasOpt {
- cdrcCfg.CdrOutDir, _ = c.GetString("cdrc", "cdr_out_dir")
- }
- if hasOpt := c.HasOption("cdrc", "cdr_source_id"); hasOpt {
- cdrcCfg.CdrSourceId, _ = c.GetString("cdrc", "cdr_source_id")
- }
- // Parse CdrFields
- torFld, _ := c.GetString("cdrc", "tor_field")
- accIdFld, _ := c.GetString("cdrc", "accid_field")
- reqtypeFld, _ := c.GetString("cdrc", "reqtype_field")
- directionFld, _ := c.GetString("cdrc", "direction_field")
- tenantFld, _ := c.GetString("cdrc", "tenant_field")
- categoryFld, _ := c.GetString("cdrc", "category_field")
- acntFld, _ := c.GetString("cdrc", "account_field")
- subjectFld, _ := c.GetString("cdrc", "subject_field")
- destFld, _ := c.GetString("cdrc", "destination_field")
- setupTimeFld, _ := c.GetString("cdrc", "setup_time_field")
- answerTimeFld, _ := c.GetString("cdrc", "answer_time_field")
- durFld, _ := c.GetString("cdrc", "usage_field")
- newVals := false
- for _, fldData := range [][]string{ // Need to keep fields order
- []string{utils.TOR, torFld}, []string{utils.ACCID, accIdFld}, []string{utils.REQTYPE, reqtypeFld}, []string{utils.DIRECTION, directionFld},
- []string{utils.TENANT, tenantFld}, []string{utils.CATEGORY, categoryFld}, []string{utils.ACCOUNT, acntFld}, []string{utils.SUBJECT, subjectFld},
- []string{utils.DESTINATION, destFld}, []string{utils.SETUP_TIME, setupTimeFld}, []string{utils.ANSWER_TIME, answerTimeFld}, []string{utils.USAGE, durFld}} {
- if len(fldData[1]) != 0 {
- if rsrFlds, err := utils.ParseRSRFields(fldData[1], utils.INFIELD_SEP); err != nil {
- return nil, err
- } else if len(rsrFlds) > 0 {
- if !newVals { // Default values there, reset them since we have at least one new
- cdrcCfg.CdrFields = nil
- newVals = true
- }
- if cdrcFld, err := NewCfgCdrFieldWithDefaults(false, rsrFlds, nil, nil, &fldData[0], nil, nil, nil, nil, nil, nil); err != nil {
- return nil, err
- } else {
- cdrcCfg.CdrFields = append(cdrcCfg.CdrFields, cdrcFld)
- }
- }
- }
- }
- extraFlds, _ := c.GetString("cdrc", "extra_fields")
- if len(extraFlds) != 0 {
- if sepExtraFlds, err := ConfigSlice(extraFlds); err != nil {
- return nil, err
- } else {
- for _, fldStr := range sepExtraFlds {
- // extra fields defined as: :
- if spltLbl := strings.Split(fldStr, utils.CONCATENATED_KEY_SEP); len(spltLbl) != 2 {
- return nil, fmt.Errorf("Wrong format for cdrc.extra_fields: %s", fldStr)
- } else {
- if rsrFlds, err := utils.ParseRSRFields(spltLbl[1], utils.INFIELD_SEP); err != nil {
- return nil, err
- } else if len(rsrFlds) > 0 {
- if cdrcFld, err := NewCfgCdrFieldWithDefaults(false, rsrFlds, nil, nil, &spltLbl[0], nil, nil, nil, nil, nil, nil); err != nil {
- return nil, err
- } else {
- cdrcCfg.CdrFields = append(cdrcCfg.CdrFields, cdrcFld)
- }
- }
- }
- }
- }
- }
- return cdrcCfg, nil
-}
-
type CdrcConfig struct {
- Id string // Configuration label
Enabled bool // Enable/Disable the profile
CdrsAddress string // The address where CDRs can be reached
CdrFormat string // The type of CDR file to process
- FieldSeparator string // The separator to use when reading csvs
+ FieldSeparator rune // The separator to use when reading csvs
DataUsageMultiplyFactor float64 // Conversion factor for data usage
RunDelay time.Duration // Delay between runs, 0 for inotify driven requests
CdrInDir string // Folder to process CDRs from
@@ -206,3 +34,44 @@ type CdrcConfig struct {
CdrSourceId string // Source identifier for the processed CDRs
CdrFields []*CfgCdrField // List of fields to be processed
}
+
+func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error {
+ if jsnCfg == nil {
+ return nil
+ }
+ var err error
+ if jsnCfg.Enabled != nil {
+ self.Enabled = *jsnCfg.Enabled
+ }
+ if jsnCfg.Cdrs_address != nil {
+ self.CdrsAddress = *jsnCfg.Cdrs_address
+ }
+ if jsnCfg.Cdrs_address != nil {
+ self.CdrsAddress = *jsnCfg.Cdrs_address
+ }
+ if jsnCfg.Cdr_format != nil {
+ self.CdrFormat = *jsnCfg.Cdr_format
+ }
+ if jsnCfg.Field_separator != nil && len(*jsnCfg.Field_separator) > 0 {
+ sepStr := *jsnCfg.Field_separator
+ self.FieldSeparator = rune(sepStr[0])
+ }
+ if jsnCfg.Data_usage_multiply_factor != nil {
+ self.DataUsageMultiplyFactor = *jsnCfg.Data_usage_multiply_factor
+ }
+ if jsnCfg.Run_delay != nil {
+ self.RunDelay = time.Duration(*jsnCfg.Run_delay) * time.Second
+ }
+ if jsnCfg.Cdr_in_dir != nil {
+ self.CdrInDir = *jsnCfg.Cdr_in_dir
+ }
+ if jsnCfg.Cdr_out_dir != nil {
+ self.CdrOutDir = *jsnCfg.Cdr_out_dir
+ }
+ if jsnCfg.Cdr_fields != nil {
+ if self.CdrFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Cdr_fields); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/config/cdrcconfig_test.go b/config/cdrcconfig_test.go
index 40c7b4f22..f49ee8e69 100644
--- a/config/cdrcconfig_test.go
+++ b/config/cdrcconfig_test.go
@@ -1,6 +1,6 @@
/*
Real-time Charging System for Telecom & ISP environments
-Copyright (C) 2012-2014 ITsysCOM GmbH
+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
@@ -17,128 +17,3 @@ along with this program. If not, see
*/
package config
-
-import (
- "reflect"
- "testing"
- "time"
-
- "github.com/cgrates/cgrates/utils"
-)
-
-func TestNewDefaultCdrcConfig(t *testing.T) {
- eDfCdrcConfig := &CdrcConfig{
- Id: utils.META_DEFAULT,
- Enabled: false,
- CdrsAddress: "",
- CdrFormat: utils.CSV,
- FieldSeparator: utils.FIELDS_SEP,
- DataUsageMultiplyFactor: 1.0,
- RunDelay: time.Duration(0),
- CdrInDir: "/var/log/cgrates/cdrc/in",
- CdrOutDir: "/var/log/cgrates/cdrc/out",
- CdrSourceId: utils.CSV,
- CdrFields: []*CfgCdrField{
- &CfgCdrField{
- Tag: utils.TOR,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.TOR,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "2"}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.ACCID,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ACCID,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "3"}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.REQTYPE,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.REQTYPE,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "4"}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.DIRECTION,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.DIRECTION,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "5"}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.TENANT,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.TENANT,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "6"}},
- Mandatory: true},
- &CfgCdrField{
- Tag: utils.CATEGORY,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.CATEGORY,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "7"}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.ACCOUNT,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ACCOUNT,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "8"}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.SUBJECT,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.SUBJECT,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "9"}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.DESTINATION,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.DESTINATION,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "10"}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.SETUP_TIME,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.SETUP_TIME,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "11"}},
- Layout: "2006-01-02T15:04:05Z07:00",
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.ANSWER_TIME,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ANSWER_TIME,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "12"}},
- Layout: "2006-01-02T15:04:05Z07:00",
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.USAGE,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.USAGE,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "13"}},
- Mandatory: true,
- },
- },
- }
- if dfCdrcCfg := NewDefaultCdrcConfig(); !reflect.DeepEqual(eDfCdrcConfig, dfCdrcCfg) {
- t.Errorf("Expected: %+v, received: %+v", eDfCdrcConfig, dfCdrcCfg)
- }
-}
diff --git a/config/cdreconfig.go b/config/cdreconfig.go
index e83336aca..8e05a23d0 100644
--- a/config/cdreconfig.go
+++ b/config/cdreconfig.go
@@ -18,77 +18,6 @@ along with this program. If not, see
package config
-import (
- "github.com/cgrates/cgrates/utils"
-)
-
-func NewDefaultCdreConfig() *CdreConfig {
- cdreCfg := new(CdreConfig)
- cdreCfg.setDefaults()
- return cdreCfg
-}
-
-func NewCdreConfigFromXmlCdreCfg(xmlCdreCfg *CgrXmlCdreCfg) (*CdreConfig, error) {
- var err error
- cdreCfg := NewDefaultCdreConfig()
- if xmlCdreCfg.CdrFormat != nil {
- cdreCfg.CdrFormat = *xmlCdreCfg.CdrFormat
- }
- if xmlCdreCfg.FieldSeparator != nil && len(*xmlCdreCfg.FieldSeparator) == 1 {
- sepStr := *xmlCdreCfg.FieldSeparator
- cdreCfg.FieldSeparator = rune(sepStr[0])
- }
- if xmlCdreCfg.DataUsageMultiplyFactor != nil {
- cdreCfg.DataUsageMultiplyFactor = *xmlCdreCfg.DataUsageMultiplyFactor
- }
- if xmlCdreCfg.CostMultiplyFactor != nil {
- cdreCfg.CostMultiplyFactor = *xmlCdreCfg.CostMultiplyFactor
- }
- if xmlCdreCfg.CostRoundingDecimals != nil {
- cdreCfg.CostRoundingDecimals = *xmlCdreCfg.CostRoundingDecimals
- }
- if xmlCdreCfg.CostShiftDigits != nil {
- cdreCfg.CostShiftDigits = *xmlCdreCfg.CostShiftDigits
- }
- if xmlCdreCfg.MaskDestId != nil {
- cdreCfg.MaskDestId = *xmlCdreCfg.MaskDestId
- }
- if xmlCdreCfg.MaskLength != nil {
- cdreCfg.MaskLength = *xmlCdreCfg.MaskLength
- }
- if xmlCdreCfg.ExportDir != nil {
- cdreCfg.ExportDir = *xmlCdreCfg.ExportDir
- }
- if xmlCdreCfg.Header != nil {
- cdreCfg.HeaderFields = make([]*CfgCdrField, len(xmlCdreCfg.Header.Fields))
- for idx, xmlFld := range xmlCdreCfg.Header.Fields {
- cdreCfg.HeaderFields[idx], err = NewCfgCdrFieldFromCgrXmlCfgCdrField(xmlFld, cdreCfg.CdrFormat == utils.CDRE_FIXED_WIDTH)
- if err != nil {
- return nil, err
- }
- }
- }
- if xmlCdreCfg.Content != nil {
- cdreCfg.ContentFields = make([]*CfgCdrField, len(xmlCdreCfg.Content.Fields))
- for idx, xmlFld := range xmlCdreCfg.Content.Fields {
- cdreCfg.ContentFields[idx], err = NewCfgCdrFieldFromCgrXmlCfgCdrField(xmlFld, cdreCfg.CdrFormat == utils.CDRE_FIXED_WIDTH)
- if err != nil {
- return nil, err
- }
- }
- }
- if xmlCdreCfg.Trailer != nil {
- cdreCfg.TrailerFields = make([]*CfgCdrField, len(xmlCdreCfg.Trailer.Fields))
- for idx, xmlFld := range xmlCdreCfg.Trailer.Fields {
- cdreCfg.TrailerFields[idx], err = NewCfgCdrFieldFromCgrXmlCfgCdrField(xmlFld, cdreCfg.CdrFormat == utils.CDRE_FIXED_WIDTH)
- if err != nil {
- return nil, err
- }
- }
- }
- return cdreCfg, nil
-}
-
// One instance of CdrExporter
type CdreConfig struct {
CdrFormat string
@@ -105,22 +34,53 @@ type CdreConfig struct {
TrailerFields []*CfgCdrField
}
-// Set here defaults
-func (cdreCfg *CdreConfig) setDefaults() error {
- cdreCfg.CdrFormat = utils.CSV
- cdreCfg.FieldSeparator = utils.CSV_SEP
- cdreCfg.DataUsageMultiplyFactor = 0.0
- cdreCfg.CostMultiplyFactor = 0.0
- cdreCfg.CostRoundingDecimals = -1
- cdreCfg.CostShiftDigits = 0
- cdreCfg.MaskDestId = ""
- cdreCfg.MaskLength = 0
- cdreCfg.ExportDir = "/var/log/cgrates/cdre"
- if flds, err := NewCfgCdrFieldsFromIds(false, utils.CGRID, utils.MEDI_RUNID, utils.TOR, utils.ACCID, utils.REQTYPE, utils.DIRECTION, utils.TENANT,
- utils.CATEGORY, utils.ACCOUNT, utils.SUBJECT, utils.DESTINATION, utils.SETUP_TIME, utils.ANSWER_TIME, utils.USAGE, utils.COST); err != nil {
- return err
- } else {
- cdreCfg.ContentFields = flds
+func (self *CdreConfig) loadFromJsonCfg(jsnCfg *CdreJsonCfg) error {
+ if jsnCfg == nil {
+ return nil
+ }
+ var err error
+ if jsnCfg.Cdr_format != nil {
+ self.CdrFormat = *jsnCfg.Cdr_format
+ }
+ if jsnCfg.Field_separator != nil && len(*jsnCfg.Field_separator) > 0 { // Make sure we got at least one character so we don't get panic here
+ sepStr := *jsnCfg.Field_separator
+ self.FieldSeparator = rune(sepStr[0])
+ }
+ if jsnCfg.Data_usage_multiply_factor != nil {
+ self.DataUsageMultiplyFactor = *jsnCfg.Data_usage_multiply_factor
+ }
+ if jsnCfg.Cost_multiply_factor != nil {
+ self.CostMultiplyFactor = *jsnCfg.Cost_multiply_factor
+ }
+ if jsnCfg.Cost_rounding_decimals != nil {
+ self.CostRoundingDecimals = *jsnCfg.Cost_rounding_decimals
+ }
+ if jsnCfg.Cost_shift_digits != nil {
+ self.CostShiftDigits = *jsnCfg.Cost_shift_digits
+ }
+ if jsnCfg.Mask_destination_id != nil {
+ self.MaskDestId = *jsnCfg.Mask_destination_id
+ }
+ if jsnCfg.Mask_length != nil {
+ self.MaskLength = *jsnCfg.Mask_length
+ }
+ if jsnCfg.Export_dir != nil {
+ self.ExportDir = *jsnCfg.Export_dir
+ }
+ if jsnCfg.Header_fields != nil {
+ if self.HeaderFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Header_fields); err != nil {
+ return err
+ }
+ }
+ if jsnCfg.Content_fields != nil {
+ if self.ContentFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Content_fields); err != nil {
+ return err
+ }
+ }
+ if jsnCfg.Trailer_fields != nil {
+ if self.TrailerFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Trailer_fields); err != nil {
+ return err
+ }
}
return nil
}
diff --git a/config/cdreconfig_test.go b/config/cdreconfig_test.go
index 455bdf296..819e5259e 100644
--- a/config/cdreconfig_test.go
+++ b/config/cdreconfig_test.go
@@ -1,6 +1,6 @@
/*
Real-time Charging System for Telecom & ISP environments
-Copyright (C) 2012-2014 ITsysCOM GmbH
+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
@@ -15,184 +15,4 @@ 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 (
- "fmt"
- "github.com/cgrates/cgrates/utils"
- "reflect"
- "testing"
-)
-
-func TestNewCfgCdrFieldsFromIds(t *testing.T) {
- expectedFlds := []*CfgCdrField{
- &CfgCdrField{
- Tag: utils.CGRID,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.CGRID,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.CGRID}},
- Width: 40,
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: "extra1",
- Type: utils.CDRFIELD,
- CdrFieldId: "extra1",
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "extra1"}},
- Width: 30,
- Strip: "xright",
- Padding: "left",
- Mandatory: false,
- },
- }
- if cdreFlds, err := NewCfgCdrFieldsFromIds(true, utils.CGRID, "extra1"); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(expectedFlds, cdreFlds) {
- t.Errorf("Expected: %v, received: %v", expectedFlds, cdreFlds)
- }
-}
-
-func TestCdreCfgNewDefaultCdreConfig(t *testing.T) {
- eCdreCfg := new(CdreConfig)
- eCdreCfg.CdrFormat = utils.CSV
- eCdreCfg.FieldSeparator = utils.CSV_SEP
- eCdreCfg.DataUsageMultiplyFactor = 0.0
- eCdreCfg.CostMultiplyFactor = 0.0
- eCdreCfg.CostRoundingDecimals = -1
- eCdreCfg.CostShiftDigits = 0
- eCdreCfg.MaskDestId = ""
- eCdreCfg.MaskLength = 0
- eCdreCfg.ExportDir = "/var/log/cgrates/cdre"
- eCdreCfg.ContentFields = []*CfgCdrField{
- &CfgCdrField{
- Tag: utils.CGRID,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.CGRID,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.CGRID}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.MEDI_RUNID,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.MEDI_RUNID,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.MEDI_RUNID}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.TOR,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.TOR,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.TOR}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.ACCID,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ACCID,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.ACCID}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.REQTYPE,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.REQTYPE,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.REQTYPE}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.DIRECTION,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.DIRECTION,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.DIRECTION}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.TENANT,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.TENANT,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.TENANT}},
- Mandatory: true},
- &CfgCdrField{
- Tag: utils.CATEGORY,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.CATEGORY,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.CATEGORY}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.ACCOUNT,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ACCOUNT,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.ACCOUNT}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.SUBJECT,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.SUBJECT,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.SUBJECT}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.DESTINATION,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.DESTINATION,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.DESTINATION}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.SETUP_TIME,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.SETUP_TIME,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.SETUP_TIME}},
- Layout: "2006-01-02T15:04:05Z07:00",
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.ANSWER_TIME,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ANSWER_TIME,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.ANSWER_TIME}},
- Layout: "2006-01-02T15:04:05Z07:00",
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.USAGE,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.USAGE,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.USAGE}},
- Mandatory: true,
- },
- &CfgCdrField{
- Tag: utils.COST,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.COST,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.COST}},
- Mandatory: true,
- },
- }
- if cdreCfg := NewDefaultCdreConfig(); !reflect.DeepEqual(eCdreCfg, cdreCfg) {
- for _, fld := range cdreCfg.ContentFields {
- fmt.Printf("Have field: %+v\n", fld)
- }
- t.Errorf("Expecting: %v, received: %v", eCdreCfg, cdreCfg)
- }
-}
diff --git a/config/cdrstatsconfig.go b/config/cdrstatsconfig.go
index ab09674b8..d8fcc2238 100644
--- a/config/cdrstatsconfig.go
+++ b/config/cdrstatsconfig.go
@@ -19,163 +19,10 @@ along with this program. If not, see
package config
import (
- "code.google.com/p/goconf/conf"
"github.com/cgrates/cgrates/utils"
- "strconv"
"time"
)
-// Parse the configuration file for CDRStatConfigs
-func ParseCfgDefaultCDRStatsConfig(c *conf.ConfigFile) (*CdrStatsConfig, error) {
- var err error
- csCfg := NewCdrStatsConfigWithDefaults()
- if hasOpt := c.HasOption("cdrstats", "queue_length"); hasOpt {
- csCfg.QueueLength, _ = c.GetInt("cdrstats", "queue_length")
- }
- if hasOpt := c.HasOption("cdrstats", "time_window"); hasOpt {
- durStr, _ := c.GetString("cdrstats", "time_window")
- if csCfg.TimeWindow, err = utils.ParseDurationWithSecs(durStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "metrics"); hasOpt {
- metricsStr, _ := c.GetString("cdrstats", "metrics")
- if csCfg.Metrics, err = ConfigSlice(metricsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "setup_interval"); hasOpt {
- setupIntervalStr, _ := c.GetString("cdrstats", "setup_interval")
- if len(setupIntervalStr) != 0 { // If we parse empty, will get empty time, we prefer nil
- if setupIntervalSlc, err := ConfigSlice(setupIntervalStr); err != nil {
- return nil, err
- } else {
- for _, setupTimeStr := range setupIntervalSlc {
- if setupTime, err := utils.ParseTimeDetectLayout(setupTimeStr); err != nil {
- return nil, err
- } else {
- csCfg.SetupInterval = append(csCfg.SetupInterval, setupTime)
- }
- }
- }
- }
- }
- if hasOpt := c.HasOption("cdrstats", "tors"); hasOpt {
- torsStr, _ := c.GetString("cdrstats", "tors")
- if csCfg.TORs, err = ConfigSlice(torsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "cdr_hosts"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "cdr_hosts")
- if csCfg.CdrHosts, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "cdr_sources"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "cdr_sources")
- if csCfg.CdrSources, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "req_types"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "req_types")
- if csCfg.ReqTypes, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "directions"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "directions")
- if csCfg.Directions, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "tenants"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "tenants")
- if csCfg.Tenants, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "categories"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "categories")
- if csCfg.Categories, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "accounts"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "accounts")
- if csCfg.Accounts, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "subjects"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "subjects")
- if csCfg.Subjects, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "destination_prefixes"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "destination_prefixes")
- if csCfg.DestinationPrefixes, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "usage_interval"); hasOpt {
- usageIntervalStr, _ := c.GetString("cdrstats", "usage_interval")
- if usageIntervalSlc, err := ConfigSlice(usageIntervalStr); err != nil {
- return nil, err
- } else {
- for _, usageDurStr := range usageIntervalSlc {
- if usageDur, err := utils.ParseDurationWithSecs(usageDurStr); err != nil {
- return nil, err
- } else {
- csCfg.UsageInterval = append(csCfg.UsageInterval, usageDur)
- }
- }
- }
- }
- if hasOpt := c.HasOption("cdrstats", "mediation_run_ids"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "mediation_run_ids")
- if csCfg.MediationRunIds, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "rated_accounts"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "rated_accounts")
- if csCfg.RatedAccounts, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "rated_subjects"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "rated_subjects")
- if csCfg.RatedSubjects, err = ConfigSlice(valsStr); err != nil {
- return nil, err
- }
- }
- if hasOpt := c.HasOption("cdrstats", "cost_intervals"); hasOpt {
- valsStr, _ := c.GetString("cdrstats", "cost_intervals")
- if costSlc, err := ConfigSlice(valsStr); err != nil {
- return nil, err
- } else {
- for _, costStr := range costSlc {
- if cost, err := strconv.ParseFloat(costStr, 64); err != nil {
- return nil, err
- } else {
- csCfg.CostInterval = append(csCfg.CostInterval, cost)
- }
- }
- }
- }
-
- return csCfg, nil
-}
-
-func NewCdrStatsConfigWithDefaults() *CdrStatsConfig {
- csCfg := new(CdrStatsConfig)
- csCfg.setDefaults()
- return csCfg
-}
-
type CdrStatsConfig struct {
Id string // Config id, unique per config instance
QueueLength int // Number of items in the stats buffer
@@ -199,9 +46,74 @@ type CdrStatsConfig struct {
CostInterval []float64 // 2 or less items, (>=Cost,
+},
+
+"cdrc": {
+ "CDRC-CSV1": {
+ "enabled": true, // enable CDR client functionality
+ "cdr_in_dir": "/tmp/cgrates/cdrc1/in", // absolute path towards the directory where the CDRs are stored
+ "cdr_out_dir": "/tmp/cgrates/cdrc1/out", // absolute path towards the directory where processed CDRs will be moved
+ "cdr_source_id": "csv1", // free form field, tag identifying the source of the CDRs within CDRS database
+ },
+ "CDRC-CSV2": {
+ "enabled": true, // enable CDR client functionality
+ "cdr_in_dir": "/tmp/cgrates/cdrc2/in", // absolute path towards the directory where the CDRs are stored
+ "cdr_out_dir": "/tmp/cgrates/cdrc2/out", // absolute path towards the directory where processed CDRs will be moved
+ "cdr_source_id": "csv2", // free form field, tag identifying the source of the CDRs within CDRS database
+ "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
+ {"cdr_field_id": "tor", "value": "~7:s/^(voice|data|sms)$/*$1/"},
+ {"cdr_field_id": "answer_time", "value": "1"},
+ {"cdr_field_id": "usage", "value": "~9:s/^(\\d+)$/${1}s/"},
+ ],
+ },
+},
+
+}
\ No newline at end of file
diff --git a/config/cfgcdrfield.go b/config/cfgcdrfield.go
index c471674bf..6ca1e2c53 100644
--- a/config/cfgcdrfield.go
+++ b/config/cfgcdrfield.go
@@ -1,6 +1,6 @@
/*
Real-time Charging System for Telecom & ISP environments
-Copyright (C) 2012-2014 ITsysCOM GmbH
+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
@@ -20,128 +20,46 @@ package config
import (
"github.com/cgrates/cgrates/utils"
- "strings"
)
-func NewCfgCdrFieldFromCgrXmlCfgCdrField(xmlCdrFld *XmlCfgCdrField, fixedWidth bool) (*CfgCdrField, error) {
+func NewCfgCdrFieldFromCdrFieldJsonCfg(jsnCfgFld *CdrFieldJsonCfg) (*CfgCdrField, error) {
var err error
- var val, fltr utils.RSRFields
- if xmlCdrFld.Value != nil {
- if xmlCdrFld.Type != nil && utils.IsSliceMember([]string{utils.CONSTANT, utils.FILLER, utils.METATAG, utils.HTTP_POST}, *xmlCdrFld.Type) && !strings.HasPrefix(*xmlCdrFld.Value, utils.STATIC_VALUE_PREFIX) { // Enforce static values for fields which do not support RSR rules
- *xmlCdrFld.Value = utils.STATIC_VALUE_PREFIX + *xmlCdrFld.Value
- }
- if val, err = utils.ParseRSRFields(*xmlCdrFld.Value, utils.INFIELD_SEP); err != nil {
+ cfgFld := new(CfgCdrField)
+ if jsnCfgFld.Tag != nil {
+ cfgFld.Tag = *jsnCfgFld.Tag
+ }
+ if jsnCfgFld.Type != nil {
+ cfgFld.Type = *jsnCfgFld.Type
+ }
+ if jsnCfgFld.Cdr_field_id != nil {
+ cfgFld.CdrFieldId = *jsnCfgFld.Cdr_field_id
+ }
+ if jsnCfgFld.Value != nil {
+ if cfgFld.Value, err = utils.ParseRSRFields(*jsnCfgFld.Value, utils.INFIELD_SEP); err != nil {
return nil, err
}
}
- if xmlCdrFld.Filter != nil {
- if fltr, err = utils.ParseRSRFields(*xmlCdrFld.Filter, utils.INFIELD_SEP); err != nil {
+ if jsnCfgFld.Filter != nil {
+ if cfgFld.Filter, err = utils.ParseRSRFields(*jsnCfgFld.Filter, utils.INFIELD_SEP); err != nil {
return nil, err
}
}
- if cdrFld, err := NewCfgCdrFieldWithDefaults(fixedWidth, val, fltr, xmlCdrFld.Type, xmlCdrFld.CdrFieldId, xmlCdrFld.Tag,
- xmlCdrFld.Mandatory, xmlCdrFld.Layout, xmlCdrFld.Width, xmlCdrFld.Strip, xmlCdrFld.Padding); err != nil {
- return nil, err
- } else {
- return cdrFld, nil
+ if jsnCfgFld.Width != nil {
+ cfgFld.Width = *jsnCfgFld.Width
}
-}
-
-func NewCfgCdrFieldWithDefaults(fixedWidth bool, val, filter utils.RSRFields, typ, cdrFieldId, tag *string, mandatory *bool, layout *string, width *int, strip, padding *string) (*CfgCdrField, error) {
- cdrField := &CfgCdrField{Value: val, Filter: filter}
- if typ != nil {
- cdrField.Type = *typ
- } else {
- cdrField.Type = utils.CDRFIELD
+ if jsnCfgFld.Strip != nil {
+ cfgFld.Strip = *jsnCfgFld.Strip
}
- if cdrFieldId != nil {
- cdrField.CdrFieldId = *cdrFieldId
- } else if utils.IsSliceMember([]string{utils.CDRFIELD, utils.COMBIMED, utils.METATAG}, cdrField.Type) && len(cdrField.Value) != 0 {
- cdrField.CdrFieldId = cdrField.Value[0].Id
+ if jsnCfgFld.Padding != nil {
+ cfgFld.Padding = *jsnCfgFld.Padding
}
- if tag != nil {
- cdrField.Tag = *tag
- } else {
- cdrField.Tag = cdrField.CdrFieldId
+ if jsnCfgFld.Layout != nil {
+ cfgFld.Layout = *jsnCfgFld.Layout
}
- mandatoryFields := append(utils.PrimaryCdrFields, utils.CGRID, utils.COST, utils.MEDI_RUNID, utils.ORDERID)
- if mandatory != nil {
- cdrField.Mandatory = *mandatory
- } else if utils.IsSliceMember(mandatoryFields, cdrField.CdrFieldId) {
- cdrField.Mandatory = true
+ if jsnCfgFld.Mandatory != nil {
+ cfgFld.Mandatory = *jsnCfgFld.Mandatory
}
- if layout != nil {
- cdrField.Layout = *layout
- } else if utils.IsSliceMember([]string{utils.SETUP_TIME, utils.ANSWER_TIME}, cdrField.CdrFieldId) {
- cdrField.Layout = "2006-01-02T15:04:05Z07:00"
- }
- if width != nil {
- cdrField.Width = *width
- } else if fixedWidth && cdrField.Type != utils.CONSTANT {
- switch cdrField.CdrFieldId { // First value element is used as field reference, giving the default properties out, good enough for default configs which do not have more than one value anyway
- case utils.CGRID:
- cdrField.Width = 40
- case utils.ORDERID:
- cdrField.Width = 11
- case utils.TOR:
- cdrField.Width = 6
- case utils.ACCID:
- cdrField.Width = 36
- case utils.CDRHOST:
- cdrField.Width = 15
- case utils.CDRSOURCE:
- cdrField.Width = 15
- case utils.REQTYPE:
- cdrField.Width = 13
- case utils.DIRECTION:
- cdrField.Width = 4
- case utils.TENANT:
- cdrField.Width = 24
- case utils.CATEGORY:
- cdrField.Width = 10
- case utils.ACCOUNT:
- cdrField.Width = 24
- case utils.SUBJECT:
- cdrField.Width = 24
- case utils.DESTINATION:
- cdrField.Width = 24
- case utils.SETUP_TIME:
- cdrField.Width = 30
- case utils.ANSWER_TIME:
- cdrField.Width = 30
- case utils.USAGE:
- cdrField.Width = 30
- case utils.MEDI_RUNID:
- cdrField.Width = 20
- case utils.COST:
- cdrField.Width = 24
- default:
- cdrField.Width = 30
- }
- }
- if strip != nil {
- cdrField.Strip = *strip
- } else if fixedWidth && cdrField.Type != utils.CONSTANT {
- switch cdrField.CdrFieldId { // First value element is used as field reference, giving the default properties out, good enough for default configs which do not have more than one value anyway
- case utils.CGRID, utils.ORDERID, utils.TOR:
- case utils.ACCID, utils.CDRHOST:
- cdrField.Strip = "left"
- case utils.CDRSOURCE, utils.REQTYPE, utils.DIRECTION, utils.TENANT, utils.CATEGORY, utils.ACCOUNT, utils.SUBJECT, utils.DESTINATION, utils.SETUP_TIME, utils.ANSWER_TIME, utils.USAGE, utils.MEDI_RUNID, utils.COST:
- cdrField.Strip = "xright"
- default:
- cdrField.Strip = "xright"
- }
- }
- if padding != nil {
- cdrField.Padding = *padding
- } else if fixedWidth && cdrField.Type != utils.CONSTANT {
- switch cdrField.CdrFieldId { // First value element is used as field reference, giving the default properties out, good enough for default configs which do not have more than one value anyway
- case utils.CGRID:
- default:
- cdrField.Padding = "left"
- }
- }
- return cdrField, nil
+ return cfgFld, nil
}
type CfgCdrField struct {
@@ -157,19 +75,14 @@ type CfgCdrField struct {
Mandatory bool
}
-// Converts a list of field identifiers into proper CDR field content
-func NewCfgCdrFieldsFromIds(withFixedWith bool, fldsIds ...string) ([]*CfgCdrField, error) {
- cdrFields := make([]*CfgCdrField, len(fldsIds))
- for idx, fldId := range fldsIds {
- if parsedRsr, err := utils.NewRSRField(fldId); err != nil {
+func CfgCdrFieldsFromCdrFieldsJsonCfg(jsnCfgFldss []*CdrFieldJsonCfg) ([]*CfgCdrField, error) {
+ retFields := make([]*CfgCdrField, len(jsnCfgFldss))
+ for idx, jsnFld := range jsnCfgFldss {
+ if cfgFld, err := NewCfgCdrFieldFromCdrFieldJsonCfg(jsnFld); err != nil {
return nil, err
} else {
- if cdrFld, err := NewCfgCdrFieldWithDefaults(withFixedWith, utils.RSRFields{parsedRsr}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- return nil, err
- } else {
- cdrFields[idx] = cdrFld
- }
+ retFields[idx] = cfgFld
}
}
- return cdrFields, nil
+ return retFields, nil
}
diff --git a/config/cfgcdrfield_test.go b/config/cfgcdrfield_test.go
index 0ad8c91c7..f49ee8e69 100644
--- a/config/cfgcdrfield_test.go
+++ b/config/cfgcdrfield_test.go
@@ -1,6 +1,6 @@
/*
Real-time Charging System for Telecom & ISP environments
-Copyright (C) 2012-2014 ITsysCOM GmbH
+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
@@ -17,315 +17,3 @@ along with this program. If not, see
*/
package config
-
-import (
- //"fmt"
- "github.com/cgrates/cgrates/utils"
- "reflect"
- "testing"
-)
-
-func TestNewCfgCdrFieldWithDefaults(t *testing.T) {
- eCdreCdrFld := &CfgCdrField{
- Tag: utils.CGRID,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.CGRID,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.CGRID}},
- Width: 40,
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.CGRID}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.ORDERID,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ORDERID,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.ORDERID}},
- Width: 11,
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.ORDERID}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.TOR,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.TOR,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.TOR}},
- Width: 6,
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.TOR}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.ACCID,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ACCID,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.ACCID}},
- Width: 36,
- Strip: "left",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.ACCID}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.CDRHOST,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.CDRHOST,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.CDRHOST}},
- Width: 15,
- Strip: "left",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.CDRHOST}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.CDRSOURCE,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.CDRSOURCE,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.CDRSOURCE}},
- Width: 15,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.CDRSOURCE}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.REQTYPE,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.REQTYPE,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.REQTYPE}},
- Width: 13,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.REQTYPE}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.DIRECTION,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.DIRECTION,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.DIRECTION}},
- Width: 4,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.DIRECTION}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.TENANT,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.TENANT,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.TENANT}},
- Width: 24,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.TENANT}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.CATEGORY,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.CATEGORY,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.CATEGORY}},
- Width: 10,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.CATEGORY}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.ACCOUNT,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ACCOUNT,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.ACCOUNT}},
- Width: 24,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.ACCOUNT}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.SUBJECT,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.SUBJECT,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.SUBJECT}},
- Width: 24,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.SUBJECT}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.DESTINATION,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.DESTINATION,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.DESTINATION}},
- Width: 24,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.DESTINATION}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.SETUP_TIME,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.SETUP_TIME,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.SETUP_TIME}},
- Width: 30,
- Strip: "xright",
- Padding: "left",
- Layout: "2006-01-02T15:04:05Z07:00",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.SETUP_TIME}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.ANSWER_TIME,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.ANSWER_TIME,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.ANSWER_TIME}},
- Width: 30,
- Strip: "xright",
- Padding: "left",
- Layout: "2006-01-02T15:04:05Z07:00",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.ANSWER_TIME}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.USAGE,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.USAGE,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.USAGE}},
- Width: 30,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.USAGE}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.MEDI_RUNID,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.MEDI_RUNID,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.MEDI_RUNID}},
- Width: 20,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.MEDI_RUNID}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: utils.COST,
- Type: utils.CDRFIELD,
- CdrFieldId: utils.COST,
- Value: []*utils.RSRField{
- &utils.RSRField{Id: utils.COST}},
- Width: 24,
- Strip: "xright",
- Padding: "left",
- Mandatory: true,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: utils.COST}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
- eCdreCdrFld = &CfgCdrField{
- Tag: "extra_1",
- Type: utils.CDRFIELD,
- CdrFieldId: "extra_1",
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "extra_1"}},
- Width: 30,
- Strip: "xright",
- Padding: "left",
- Mandatory: false,
- }
- if cfgCdrField, err := NewCfgCdrFieldWithDefaults(true, []*utils.RSRField{&utils.RSRField{Id: "extra_1"}}, nil, nil, nil, nil, nil, nil, nil, nil, nil); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(eCdreCdrFld, cfgCdrField) {
- t.Errorf("Expecting: %+v, received: %+v", eCdreCdrFld, cfgCdrField)
- }
-}
diff --git a/config/config.go b/config/config.go
index dbabd198d..14bc2cb23 100644
--- a/config/config.go
+++ b/config/config.go
@@ -22,11 +22,11 @@ import (
"errors"
"fmt"
"os"
+ "path/filepath"
"strconv"
"strings"
"time"
- "code.google.com/p/goconf/conf"
"github.com/cgrates/cgrates/utils"
)
@@ -53,185 +53,165 @@ func SetCgrConfig(cfg *CGRConfig) {
cgrCfg = cfg
}
-// Holds system configuration, defaults are overwritten with values from config file if found
-type CGRConfig struct {
- RatingDBType string
- RatingDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
- RatingDBPort string // The port to bind to.
- RatingDBName string // The name of the database to connect to.
- RatingDBUser string // The user to sign in as.
- RatingDBPass string // The user's password.
- AccountDBType string
- AccountDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
- AccountDBPort string // The port to bind to.
- AccountDBName string // The name of the database to connect to.
- AccountDBUser string // The user to sign in as.
- AccountDBPass string // The user's password.
- StorDBType string // Should reflect the database type used to store logs
- StorDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
- StorDBPort string // Th e port to bind to.
- StorDBName string // The name of the database to connect to.
- StorDBUser string // The user to sign in as.
- StorDBPass string // The user's password.
- StorDBMaxOpenConns int // Maximum database connections opened
- StorDBMaxIdleConns int // Maximum idle connections to keep opened
- DBDataEncoding string // The encoding used to store object data in strings:
- RPCJSONListen string // RPC JSON listening address
- RPCGOBListen string // RPC GOB listening address
- HTTPListen string // HTTP listening address
- DefaultReqType string // Use this request type if not defined on top
- DefaultCategory string // set default type of record
- DefaultTenant string // set default tenant
- DefaultSubject string // set default rating subject, useful in case of fallback
- RoundingDecimals int // Number of decimals to round end prices at
- HttpSkipTlsVerify bool // If enabled Http Client will accept any TLS certificate
- TpExportPath string // Path towards export folder for offline Tariff Plans
- XmlCfgDocument *CgrXmlCfgDocument // Load additional configuration inside xml document
- RaterEnabled bool // start standalone server (no balancer)
- RaterBalancer string // balancer address host:port
- BalancerEnabled bool
- SchedulerEnabled bool
- CDRSEnabled bool // Enable CDR Server service
- CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs
- CDRSMediator string // Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
- CDRSStats string // Address where to reach the Mediator. <""|intenal>
- CDRSStoreDisable bool // When true, CDRs will not longer be saved in stordb, useful for cdrstats only scenario
- CDRStatsEnabled bool // Enable CDR Stats service
- CDRStatConfig *CdrStatsConfig // Active cdr stats configuration instances
- CdreDefaultInstance *CdreConfig // Will be used in the case no specific one selected by API
- CdrcInstances []*CdrcConfig // Number of CDRC instances running imports
- SMEnabled bool
- SMSwitchType string
- SMRater string // address where to access rater. Can be internal, direct rater address or the address of a balancer
- SMCdrS string // Connection towards CDR server
- SMReconnects int // Number of reconnect attempts to rater
- SMDebitInterval int // the period to be debited in advanced during a call (in seconds)
- SMMaxCallDuration time.Duration // The maximum duration of a call
- SMMinCallDuration time.Duration // Only authorize calls with allowed duration bigger than this
- MediatorEnabled bool // Starts Mediator service: .
- MediatorReconnects int // Number of reconnects to rater before giving up.
- MediatorRater string
- MediatorStats string // Address where to reach the Rater:
- MediatorStoreDisable bool // When true, CDRs will not longer be saved in stordb, useful for cdrstats only scenario
- DerivedChargers utils.DerivedChargers // System wide derived chargers, added to the account level ones
- CombinedDerivedChargers bool // Combine accounts specific derived_chargers with server configured
- FreeswitchServer string // freeswitch address host:port
- FreeswitchPass string // FS socket password
- FreeswitchReconnects int // number of times to attempt reconnect after connect fails
- FSMinDurLowBalance time.Duration // Threshold which will trigger low balance warnings
- FSLowBalanceAnnFile string // File to be played when low balance is reached
- FSEmptyBalanceContext string // If defined, call will be transfered to this context on empty balance
- FSEmptyBalanceAnnFile string // File to be played before disconnecting prepaid calls (applies only if no context defined)
- FSCdrExtraFields []*utils.RSRField // Extra fields to store in CDRs in case of processing them
- OsipsListenUdp string // Address where to listen for event datagrams coming from OpenSIPS
- OsipsMiAddr string // Adress where to reach OpenSIPS mi_datagram module
- OsipsEvSubscInterval time.Duration // Refresh event subscription at this interval
- OsipsReconnects int // Number of attempts on connect failure.
- KamailioEvApiAddr string // Address of the kamailio evapi server
- KamailioReconnects int // Number of reconnect attempts on connection lost
- HistoryAgentEnabled bool // Starts History as an agent: .
- HistoryServer string // Address where to reach the master history server:
- HistoryServerEnabled bool // Starts History as server: .
- HistoryDir string // Location on disk where to store history files.
- HistorySaveInterval time.Duration // The timout duration between history writes
- MailerServer string // The server to use when sending emails out
- MailerAuthUser string // Authenticate to email server using this user
- MailerAuthPass string // Authenticate to email server with this password
- MailerFromAddr string // From address used when sending emails out
- DataFolderPath string // Path towards data folder, for tests internal usage, not loading out of .cfg options
+func NewDefaultCGRConfig() (*CGRConfig, error) {
+ cfg := new(CGRConfig)
+ cgrJsonCfg, err := NewCgrJsonCfgFromReader(strings.NewReader(CGRATES_CFG_JSON))
+ if err != nil {
+ return nil, err
+ }
+ if err := cfg.loadFromJsonCfg(cgrJsonCfg); err != nil {
+ return nil, err
+ }
+ if err := cfg.checkConfigSanity(); err != nil {
+ return nil, err
+ }
+ return cfg, nil
}
-func (self *CGRConfig) setDefaults() error {
- self.RatingDBType = REDIS
- self.RatingDBHost = "127.0.0.1"
- self.RatingDBPort = "6379"
- self.RatingDBName = "10"
- self.RatingDBUser = ""
- self.RatingDBPass = ""
- self.AccountDBType = REDIS
- self.AccountDBHost = "127.0.0.1"
- self.AccountDBPort = "6379"
- self.AccountDBName = "11"
- self.AccountDBUser = ""
- self.AccountDBPass = ""
- self.StorDBType = utils.MYSQL
- self.StorDBHost = "localhost"
- self.StorDBPort = "3306"
- self.StorDBName = "cgrates"
- self.StorDBUser = "cgrates"
- self.StorDBPass = "CGRateS.org"
- self.StorDBMaxOpenConns = 100
- self.StorDBMaxIdleConns = 10
- self.DBDataEncoding = utils.MSGPACK
- self.RPCJSONListen = "127.0.0.1:2012"
- self.RPCGOBListen = "127.0.0.1:2013"
- self.HTTPListen = "127.0.0.1:2080"
- self.DefaultReqType = utils.RATED
- self.DefaultCategory = "call"
- self.DefaultTenant = "cgrates.org"
- self.DefaultSubject = "cgrates"
- self.RoundingDecimals = 10
- self.HttpSkipTlsVerify = false
- self.TpExportPath = "/var/log/cgrates/tpe"
- self.XmlCfgDocument = nil
- self.RaterEnabled = false
- self.RaterBalancer = ""
- self.BalancerEnabled = false
- self.SchedulerEnabled = false
- self.CDRSEnabled = false
- self.CDRSExtraFields = []*utils.RSRField{}
- self.CDRSMediator = ""
- self.CDRSStats = ""
- self.CDRSStoreDisable = false
- self.CDRStatsEnabled = false
- self.CDRStatConfig = NewCdrStatsConfigWithDefaults()
- self.CdreDefaultInstance = NewDefaultCdreConfig()
- self.CdrcInstances = []*CdrcConfig{NewDefaultCdrcConfig()} // This instance is just for the sake of defaults, it will be replaced when the file is loaded with the one resulted from there
- self.MediatorEnabled = false
- self.MediatorRater = utils.INTERNAL
- self.MediatorReconnects = 3
- self.MediatorStats = ""
- self.MediatorStoreDisable = false
- self.DerivedChargers = make(utils.DerivedChargers, 0)
- self.CombinedDerivedChargers = true
- self.SMEnabled = false
- self.SMSwitchType = FS
- self.SMRater = utils.INTERNAL
- self.SMCdrS = ""
- self.SMReconnects = 3
- self.SMDebitInterval = 10
- self.SMMaxCallDuration = time.Duration(3) * time.Hour
- self.SMMinCallDuration = time.Duration(0)
- self.FreeswitchServer = "127.0.0.1:8021"
- self.FreeswitchPass = "ClueCon"
- self.FreeswitchReconnects = 5
- self.FSMinDurLowBalance = time.Duration(5) * time.Second
- self.FSLowBalanceAnnFile = ""
- self.FSEmptyBalanceContext = ""
- self.FSEmptyBalanceAnnFile = ""
- self.FSCdrExtraFields = []*utils.RSRField{}
- self.OsipsListenUdp = "127.0.0.1:2020"
- self.OsipsMiAddr = "127.0.0.1:8020"
- self.OsipsEvSubscInterval = time.Duration(60) * time.Second
- self.OsipsReconnects = 3
- self.KamailioEvApiAddr = "127.0.0.1:8448"
- self.KamailioReconnects = 3
- self.HistoryAgentEnabled = false
- self.HistoryServerEnabled = false
- self.HistoryServer = utils.INTERNAL
- self.HistoryDir = "/var/log/cgrates/history"
- self.HistorySaveInterval = time.Duration(1) * time.Second
- self.MailerServer = "localhost:25"
- self.MailerAuthUser = "cgrates"
- self.MailerAuthPass = "CGRateS.org"
- self.MailerFromAddr = "cgr-mailer@localhost.localdomain"
- self.DataFolderPath = "/usr/share/cgrates/"
- return nil
+func NewCGRConfigFromJsonString(cfgJsonStr string) (*CGRConfig, error) {
+ cfg := new(CGRConfig)
+ if jsnCfg, err := NewCgrJsonCfgFromReader(strings.NewReader(cfgJsonStr)); err != nil {
+ return nil, err
+ } else if err := cfg.loadFromJsonCfg(jsnCfg); err != nil {
+ return nil, err
+ }
+ return cfg, nil
+}
+
+// Reads all .json files out of a folder/subfolders and loads them up in lexical order
+func NewCGRConfigFromFolder(cfgDir string) (*CGRConfig, error) {
+ if fi, err := os.Stat(cfgDir); err != nil {
+ return nil, err
+ } else if !fi.IsDir() {
+ return nil, fmt.Errorf("Path: %s not a directory.", cfgDir)
+ }
+ cfg, err := NewDefaultCGRConfig()
+ if err != nil {
+ return nil, err
+ }
+ jsonFilesFound := false
+ err = filepath.Walk(cfgDir, func(path string, info os.FileInfo, err error) error {
+ if !info.IsDir() {
+ return nil
+ }
+ cfgFiles, err := filepath.Glob(filepath.Join(path, "*.json"))
+ if err != nil {
+ return err
+ }
+ if cfgFiles == nil { // No need of processing further since there are no config files in the folder
+ return nil
+ }
+ if !jsonFilesFound {
+ jsonFilesFound = true
+ }
+ for _, jsonFilePath := range cfgFiles {
+ if cgrJsonCfg, err := NewCgrJsonCfgFromFile(jsonFilePath); err != nil {
+ return err
+ } else if err := cfg.loadFromJsonCfg(cgrJsonCfg); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ } else if !jsonFilesFound {
+ return nil, fmt.Errorf("No config file found on path %s", cfgDir)
+ }
+ if err := cfg.checkConfigSanity(); err != nil {
+ return nil, err
+ }
+ return cfg, nil
+}
+
+// Holds system configuration, defaults are overwritten with values from config file if found
+type CGRConfig struct {
+ RatingDBType string
+ RatingDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
+ RatingDBPort string // The port to bind to.
+ RatingDBName string // The name of the database to connect to.
+ RatingDBUser string // The user to sign in as.
+ RatingDBPass string // The user's password.
+ AccountDBType string
+ AccountDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
+ AccountDBPort string // The port to bind to.
+ AccountDBName string // The name of the database to connect to.
+ AccountDBUser string // The user to sign in as.
+ AccountDBPass string // The user's password.
+ StorDBType string // Should reflect the database type used to store logs
+ StorDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
+ StorDBPort string // Th e port to bind to.
+ StorDBName string // The name of the database to connect to.
+ StorDBUser string // The user to sign in as.
+ StorDBPass string // The user's password.
+ StorDBMaxOpenConns int // Maximum database connections opened
+ StorDBMaxIdleConns int // Maximum idle connections to keep opened
+ DBDataEncoding string // The encoding used to store object data in strings:
+ RPCJSONListen string // RPC JSON listening address
+ RPCGOBListen string // RPC GOB listening address
+ HTTPListen string // HTTP listening address
+ DefaultReqType string // Use this request type if not defined on top
+ DefaultCategory string // set default type of record
+ DefaultTenant string // set default tenant
+ DefaultSubject string // set default rating subject, useful in case of fallback
+ RoundingDecimals int // Number of decimals to round end prices at
+ HttpSkipTlsVerify bool // If enabled Http Client will accept any TLS certificate
+ TpExportPath string // Path towards export folder for offline Tariff Plans
+ RaterEnabled bool // start standalone server (no balancer)
+ RaterBalancer string // balancer address host:port
+ BalancerEnabled bool
+ SchedulerEnabled bool
+ CDRSEnabled bool // Enable CDR Server service
+ CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs
+ CDRSMediator string // Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
+ CDRSStats string // Address where to reach the Mediator. <""|intenal>
+ CDRSStoreDisable bool // When true, CDRs will not longer be saved in stordb, useful for cdrstats only scenario
+ CDRStatsEnabled bool // Enable CDR Stats service
+ CDRStatConfig *CdrStatsConfig // Active cdr stats configuration instances, platform level
+ CdreProfiles map[string]*CdreConfig
+ CdrcProfiles map[string]*CdrcConfig // Number of CDRC instances running imports
+ SMEnabled bool
+ SMSwitchType string
+ SMRater string // address where to access rater. Can be internal, direct rater address or the address of a balancer
+ SMCdrS string // Connection towards CDR server
+ SMReconnects int // Number of reconnect attempts to rater
+ SMDebitInterval int // the period to be debited in advanced during a call (in seconds)
+ SMMaxCallDuration time.Duration // The maximum duration of a call
+ SMMinCallDuration time.Duration // Only authorize calls with allowed duration bigger than this
+ MediatorEnabled bool // Starts Mediator service: .
+ MediatorReconnects int // Number of reconnects to rater before giving up.
+ MediatorRater string
+ MediatorStats string // Address where to reach the Rater:
+ MediatorStoreDisable bool // When true, CDRs will not longer be saved in stordb, useful for cdrstats only scenario
+ FreeswitchServer string // freeswitch address host:port
+ FreeswitchPass string // FS socket password
+ FreeswitchReconnects int // number of times to attempt reconnect after connect fails
+ FSMinDurLowBalance time.Duration // Threshold which will trigger low balance warnings
+ FSLowBalanceAnnFile string // File to be played when low balance is reached
+ FSEmptyBalanceContext string // If defined, call will be transfered to this context on empty balance
+ FSEmptyBalanceAnnFile string // File to be played before disconnecting prepaid calls (applies only if no context defined)
+ FSCdrExtraFields []*utils.RSRField // Extra fields to store in CDRs in case of processing them
+ OsipsListenUdp string // Address where to listen for event datagrams coming from OpenSIPS
+ OsipsMiAddr string // Adress where to reach OpenSIPS mi_datagram module
+ OsipsEvSubscInterval time.Duration // Refresh event subscription at this interval
+ OsipsReconnects int // Number of attempts on connect failure.
+ KamailioEvApiAddr string // Address of the kamailio evapi server
+ KamailioReconnects int // Number of reconnect attempts on connection lost
+ HistoryAgentEnabled bool // Starts History as an agent: .
+ HistoryServer string // Address where to reach the master history server:
+ HistoryServerEnabled bool // Starts History as server: .
+ HistoryDir string // Location on disk where to store history files.
+ HistorySaveInterval time.Duration // The timout duration between history writes
+ MailerServer string // The server to use when sending emails out
+ MailerAuthUser string // Authenticate to email server using this user
+ MailerAuthPass string // Authenticate to email server with this password
+ MailerFromAddr string // From address used when sending emails out
+ DataFolderPath string // Path towards data folder, for tests internal usage, not loading out of .json options
}
func (self *CGRConfig) checkConfigSanity() error {
// CDRC sanity checks
- for _, cdrcInst := range self.CdrcInstances {
+ for _, cdrcInst := range self.CdrcProfiles {
if cdrcInst.Enabled == true {
if len(cdrcInst.CdrFields) == 0 {
return errors.New("CdrC enabled but no fields to be processed defined!")
@@ -259,382 +239,406 @@ func (self *CGRConfig) checkConfigSanity() error {
return nil
}
-func NewDefaultCGRConfig() (*CGRConfig, error) {
- cfg := &CGRConfig{}
- cfg.setDefaults()
- if err := cfg.checkConfigSanity(); err != nil {
- return nil, err
- }
- return cfg, nil
-}
-
-// Unifies the config handling for both tests and real path
-func NewCGRConfig(c *conf.ConfigFile) (*CGRConfig, error) {
- cfg, err := loadConfig(c)
+// Loads from json configuration object, will be used for defaults, config from file and reload, might need lock
+func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
+ // Load sections out of JSON config, stop on error
+ jsnGeneralCfg, err := jsnCfg.GeneralJsonCfg()
if err != nil {
- return nil, err
+ return err
}
- if err := cfg.checkConfigSanity(); err != nil {
- return nil, err
- }
- return cfg, nil
-}
-
-// Instantiate a new CGRConfig setting defaults or reading from file
-func NewCGRConfigFromFile(cfgPath *string) (*CGRConfig, error) {
- c, err := conf.ReadConfigFile(*cfgPath)
+ jsnListenCfg, err := jsnCfg.ListenJsonCfg()
if err != nil {
- return nil, errors.New(fmt.Sprintf("Could not open the configuration file: %s", err))
+ return err
}
- return NewCGRConfig(c)
-}
-
-func NewCGRConfigFromBytes(data []byte) (*CGRConfig, error) {
- c, err := conf.ReadConfigBytes(data)
+ jsnRatingDbCfg, err := jsnCfg.DbJsonCfg(RATINGDB_JSN)
if err != nil {
- return nil, errors.New(fmt.Sprintf("Could not open the configuration file: %s", err))
+ return err
}
- return NewCGRConfig(c)
-}
-
-func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
- cfg := &CGRConfig{}
- cfg.setDefaults()
- var hasOpt bool
- var err error
- if hasOpt = c.HasOption("global", "ratingdb_type"); hasOpt {
- cfg.RatingDBType, _ = c.GetString("global", "ratingdb_type")
+ jsnAccountingDbCfg, err := jsnCfg.DbJsonCfg(ACCOUNTINGDB_JSN)
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "ratingdb_host"); hasOpt {
- cfg.RatingDBHost, _ = c.GetString("global", "ratingdb_host")
+ jsnStorDbCfg, err := jsnCfg.DbJsonCfg(STORDB_JSN)
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "ratingdb_port"); hasOpt {
- cfg.RatingDBPort, _ = c.GetString("global", "ratingdb_port")
+ jsnBalancerCfg, err := jsnCfg.BalancerJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "ratingdb_name"); hasOpt {
- cfg.RatingDBName, _ = c.GetString("global", "ratingdb_name")
+ jsnRaterCfg, err := jsnCfg.RaterJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "ratingdb_user"); hasOpt {
- cfg.RatingDBUser, _ = c.GetString("global", "ratingdb_user")
+ jsnSchedCfg, err := jsnCfg.SchedulerJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "ratingdb_passwd"); hasOpt {
- cfg.RatingDBPass, _ = c.GetString("global", "ratingdb_passwd")
+ jsnCdrsCfg, err := jsnCfg.CdrsJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "accountdb_type"); hasOpt {
- cfg.AccountDBType, _ = c.GetString("global", "accountdb_type")
+ jsnMediatorCfg, err := jsnCfg.MediatorJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "accountdb_host"); hasOpt {
- cfg.AccountDBHost, _ = c.GetString("global", "accountdb_host")
+ jsnCdrstatsCfg, err := jsnCfg.CdrStatsJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "accountdb_port"); hasOpt {
- cfg.AccountDBPort, _ = c.GetString("global", "accountdb_port")
+ jsnCdreCfg, err := jsnCfg.CdreJsonCfgs()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "accountdb_name"); hasOpt {
- cfg.AccountDBName, _ = c.GetString("global", "accountdb_name")
+ jsnCdrcCfg, err := jsnCfg.CdrcJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "accountdb_user"); hasOpt {
- cfg.AccountDBUser, _ = c.GetString("global", "accountdb_user")
+ jsnSMCfg, err := jsnCfg.SessionManagerJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "accountdb_passwd"); hasOpt {
- cfg.AccountDBPass, _ = c.GetString("global", "accountdb_passwd")
+ jsnFSCfg, err := jsnCfg.FSJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "stordb_type"); hasOpt {
- cfg.StorDBType, _ = c.GetString("global", "stordb_type")
+ jsnKamCfg, err := jsnCfg.KamailioJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "stordb_host"); hasOpt {
- cfg.StorDBHost, _ = c.GetString("global", "stordb_host")
+ jsnOsipsCfg, err := jsnCfg.OsipsJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "stordb_port"); hasOpt {
- cfg.StorDBPort, _ = c.GetString("global", "stordb_port")
+ jsnHistServCfg, err := jsnCfg.HistServJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "stordb_name"); hasOpt {
- cfg.StorDBName, _ = c.GetString("global", "stordb_name")
+ jsnHistAgentCfg, err := jsnCfg.HistAgentJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "stordb_user"); hasOpt {
- cfg.StorDBUser, _ = c.GetString("global", "stordb_user")
+ jsnMailerCfg, err := jsnCfg.MailerJsonCfg()
+ if err != nil {
+ return err
}
- if hasOpt = c.HasOption("global", "stordb_passwd"); hasOpt {
- cfg.StorDBPass, _ = c.GetString("global", "stordb_passwd")
- }
- if hasOpt = c.HasOption("global", "stordb_max_open_conns"); hasOpt {
- cfg.StorDBMaxOpenConns, _ = c.GetInt("global", "stordb_max_open_conns")
- }
- if hasOpt = c.HasOption("global", "stordb_max_idle_conns"); hasOpt {
- cfg.StorDBMaxIdleConns, _ = c.GetInt("global", "stordb_max_idle_conns")
- }
- if hasOpt = c.HasOption("global", "dbdata_encoding"); hasOpt {
- cfg.DBDataEncoding, _ = c.GetString("global", "dbdata_encoding")
- }
- if hasOpt = c.HasOption("global", "rpc_json_listen"); hasOpt {
- cfg.RPCJSONListen, _ = c.GetString("global", "rpc_json_listen")
- }
- if hasOpt = c.HasOption("global", "rpc_gob_listen"); hasOpt {
- cfg.RPCGOBListen, _ = c.GetString("global", "rpc_gob_listen")
- }
- if hasOpt = c.HasOption("global", "http_listen"); hasOpt {
- cfg.HTTPListen, _ = c.GetString("global", "http_listen")
- }
- if hasOpt = c.HasOption("global", "default_reqtype"); hasOpt {
- cfg.DefaultReqType, _ = c.GetString("global", "default_reqtype")
- }
- if hasOpt = c.HasOption("global", "default_category"); hasOpt {
- cfg.DefaultCategory, _ = c.GetString("global", "default_category")
- }
- if hasOpt = c.HasOption("global", "default_tenant"); hasOpt {
- cfg.DefaultTenant, _ = c.GetString("global", "default_tenant")
- }
- if hasOpt = c.HasOption("global", "default_subject"); hasOpt {
- cfg.DefaultSubject, _ = c.GetString("global", "default_subject")
- }
- if hasOpt = c.HasOption("global", "rounding_decimals"); hasOpt {
- cfg.RoundingDecimals, _ = c.GetInt("global", "rounding_decimals")
- }
- if hasOpt = c.HasOption("global", "http_skip_tls_veify"); hasOpt {
- cfg.HttpSkipTlsVerify, _ = c.GetBool("global", "http_skip_tls_veify")
- }
- if hasOpt = c.HasOption("global", "tpexport_dir"); hasOpt {
- cfg.TpExportPath, _ = c.GetString("global", "tpexport_dir")
- }
- // XML config path defined, try loading the document
- if hasOpt = c.HasOption("global", "xmlcfg_path"); hasOpt {
- xmlCfgPath, _ := c.GetString("global", "xmlcfg_path")
- xmlFile, err := os.Open(xmlCfgPath)
- if err != nil {
- return nil, err
+ // All good, start populating config variables
+ if jsnRatingDbCfg != nil {
+ if jsnRatingDbCfg.Db_type != nil {
+ self.RatingDBType = *jsnRatingDbCfg.Db_type
}
- if cgrXmlCfgDoc, err := ParseCgrXmlConfig(xmlFile); err != nil {
- return nil, err
- } else {
- cfg.XmlCfgDocument = cgrXmlCfgDoc
+ if jsnRatingDbCfg.Db_host != nil {
+ self.RatingDBHost = *jsnRatingDbCfg.Db_host
+ }
+ if jsnRatingDbCfg.Db_port != nil {
+ self.RatingDBPort = strconv.Itoa(*jsnRatingDbCfg.Db_port)
+ }
+ if jsnRatingDbCfg.Db_name != nil {
+ self.RatingDBName = *jsnRatingDbCfg.Db_name
+ }
+ if jsnRatingDbCfg.Db_user != nil {
+ self.RatingDBUser = *jsnRatingDbCfg.Db_user
+ }
+ if jsnRatingDbCfg.Db_passwd != nil {
+ self.RatingDBPass = *jsnRatingDbCfg.Db_passwd
}
}
- if hasOpt = c.HasOption("rater", "enabled"); hasOpt {
- cfg.RaterEnabled, _ = c.GetBool("rater", "enabled")
- }
- if hasOpt = c.HasOption("rater", "balancer"); hasOpt {
- cfg.RaterBalancer, _ = c.GetString("rater", "balancer")
- }
- if hasOpt = c.HasOption("balancer", "enabled"); hasOpt {
- cfg.BalancerEnabled, _ = c.GetBool("balancer", "enabled")
- }
- if hasOpt = c.HasOption("scheduler", "enabled"); hasOpt {
- cfg.SchedulerEnabled, _ = c.GetBool("scheduler", "enabled")
- }
- if hasOpt = c.HasOption("cdrs", "enabled"); hasOpt {
- cfg.CDRSEnabled, _ = c.GetBool("cdrs", "enabled")
- }
- if hasOpt = c.HasOption("cdrs", "extra_fields"); hasOpt {
- extraFieldsStr, _ := c.GetString("cdrs", "extra_fields")
- if extraFields, err := utils.ParseRSRFields(extraFieldsStr, utils.FIELDS_SEP); err != nil {
- return nil, err
- } else {
- cfg.CDRSExtraFields = extraFields
+ if jsnAccountingDbCfg != nil {
+ if jsnAccountingDbCfg.Db_type != nil {
+ self.AccountDBType = *jsnAccountingDbCfg.Db_type
+ }
+ if jsnAccountingDbCfg.Db_host != nil {
+ self.AccountDBHost = *jsnAccountingDbCfg.Db_host
+ }
+ if jsnAccountingDbCfg.Db_port != nil {
+ self.AccountDBPort = strconv.Itoa(*jsnAccountingDbCfg.Db_port)
+ }
+ if jsnAccountingDbCfg.Db_name != nil {
+ self.AccountDBName = *jsnAccountingDbCfg.Db_name
+ }
+ if jsnAccountingDbCfg.Db_user != nil {
+ self.AccountDBUser = *jsnAccountingDbCfg.Db_user
+ }
+ if jsnAccountingDbCfg.Db_passwd != nil {
+ self.AccountDBPass = *jsnAccountingDbCfg.Db_passwd
}
}
- if hasOpt = c.HasOption("cdrs", "mediator"); hasOpt {
- cfg.CDRSMediator, _ = c.GetString("cdrs", "mediator")
+ if jsnStorDbCfg != nil {
+ if jsnStorDbCfg.Db_type != nil {
+ self.StorDBType = *jsnStorDbCfg.Db_type
+ }
+ if jsnStorDbCfg.Db_host != nil {
+ self.StorDBHost = *jsnStorDbCfg.Db_host
+ }
+ if jsnStorDbCfg.Db_port != nil {
+ self.StorDBPort = strconv.Itoa(*jsnStorDbCfg.Db_port)
+ }
+ if jsnStorDbCfg.Db_name != nil {
+ self.StorDBName = *jsnStorDbCfg.Db_name
+ }
+ if jsnStorDbCfg.Db_user != nil {
+ self.StorDBUser = *jsnStorDbCfg.Db_user
+ }
+ if jsnStorDbCfg.Db_passwd != nil {
+ self.StorDBPass = *jsnStorDbCfg.Db_passwd
+ }
+ if jsnStorDbCfg.Max_open_conns != nil {
+ self.StorDBMaxOpenConns = *jsnStorDbCfg.Max_open_conns
+ }
+ if jsnStorDbCfg.Max_idle_conns != nil {
+ self.StorDBMaxIdleConns = *jsnStorDbCfg.Max_idle_conns
+ }
}
- if hasOpt = c.HasOption("cdrs", "cdrstats"); hasOpt {
- cfg.CDRSStats, _ = c.GetString("cdrs", "cdrstats")
+ if jsnGeneralCfg != nil {
+ if jsnGeneralCfg.Dbdata_encoding != nil {
+ self.DBDataEncoding = *jsnGeneralCfg.Dbdata_encoding
+ }
+ if jsnGeneralCfg.Default_reqtype != nil {
+ self.DefaultReqType = *jsnGeneralCfg.Default_reqtype
+ }
+ if jsnGeneralCfg.Default_category != nil {
+ self.DefaultCategory = *jsnGeneralCfg.Default_category
+ }
+ if jsnGeneralCfg.Default_tenant != nil {
+ self.DefaultTenant = *jsnGeneralCfg.Default_tenant
+ }
+ if jsnGeneralCfg.Default_subject != nil {
+ self.DefaultSubject = *jsnGeneralCfg.Default_subject
+ }
+ if jsnGeneralCfg.Rounding_decimals != nil {
+ self.RoundingDecimals = *jsnGeneralCfg.Rounding_decimals
+ }
+ if jsnGeneralCfg.Http_skip_tls_veify != nil {
+ self.HttpSkipTlsVerify = *jsnGeneralCfg.Http_skip_tls_veify
+ }
+ if jsnGeneralCfg.Tpexport_dir != nil {
+ self.TpExportPath = *jsnGeneralCfg.Tpexport_dir
+ }
}
- if hasOpt = c.HasOption("cdrs", "store_disable"); hasOpt {
- cfg.CDRSStoreDisable, _ = c.GetBool("cdrs", "store_disable")
+ if jsnListenCfg != nil {
+ if jsnListenCfg.Rpc_json != nil {
+ self.RPCJSONListen = *jsnListenCfg.Rpc_json
+ }
+ if jsnListenCfg.Rpc_gob != nil {
+ self.RPCGOBListen = *jsnListenCfg.Rpc_gob
+ }
+ if jsnListenCfg.Http != nil {
+ self.HTTPListen = *jsnListenCfg.Http
+ }
}
- if hasOpt = c.HasOption("cdrstats", "enabled"); hasOpt {
- cfg.CDRStatsEnabled, _ = c.GetBool("cdrstats", "enabled")
+ if jsnRaterCfg != nil {
+ if jsnRaterCfg.Enabled != nil {
+ self.RaterEnabled = *jsnRaterCfg.Enabled
+ }
+ if jsnRaterCfg.Balancer != nil {
+ self.RaterBalancer = *jsnRaterCfg.Balancer
+ }
}
- if cfg.CDRStatConfig, err = ParseCfgDefaultCDRStatsConfig(c); err != nil {
- return nil, err
+ if jsnBalancerCfg != nil && jsnBalancerCfg.Enabled != nil {
+ self.BalancerEnabled = *jsnBalancerCfg.Enabled
}
- if hasOpt = c.HasOption("cdre", "cdr_format"); hasOpt {
- cfg.CdreDefaultInstance.CdrFormat, _ = c.GetString("cdre", "cdr_format")
+ if jsnSchedCfg != nil && jsnSchedCfg.Enabled != nil {
+ self.SchedulerEnabled = *jsnSchedCfg.Enabled
}
- if hasOpt = c.HasOption("cdre", "mask_destination_id"); hasOpt {
- cfg.CdreDefaultInstance.MaskDestId, _ = c.GetString("cdre", "mask_destination_id")
+ if jsnCdrsCfg != nil {
+ if jsnCdrsCfg.Enabled != nil {
+ self.CDRSEnabled = *jsnCdrsCfg.Enabled
+ }
+ if jsnCdrsCfg.Extra_fields != nil {
+ if self.CDRSExtraFields, err = utils.ParseRSRFieldsFromSlice(*jsnCdrsCfg.Extra_fields); err != nil {
+ return err
+ }
+ }
+ if jsnCdrsCfg.Mediator != nil {
+ self.CDRSMediator = *jsnCdrsCfg.Mediator
+ }
+ if jsnCdrsCfg.Cdrstats != nil {
+ self.CDRSStats = *jsnCdrsCfg.Cdrstats
+ }
+ if jsnCdrsCfg.Store_disable != nil {
+ self.CDRSStoreDisable = *jsnCdrsCfg.Store_disable
+ }
}
- if hasOpt = c.HasOption("cdre", "mask_length"); hasOpt {
- cfg.CdreDefaultInstance.MaskLength, _ = c.GetInt("cdre", "mask_length")
+ if jsnCdrstatsCfg != nil {
+ if jsnCdrstatsCfg.Enabled != nil {
+ self.CDRStatsEnabled = *jsnCdrstatsCfg.Enabled
+ }
+ if jsnCdrstatsCfg != nil { // Have CDRStats config, load it in default object
+ if self.CDRStatConfig == nil {
+ self.CDRStatConfig = &CdrStatsConfig{Id: utils.META_DEFAULT}
+ }
+ if err = self.CDRStatConfig.loadFromJsonCfg(jsnCdrstatsCfg); err != nil {
+ return err
+ }
+ }
}
- if hasOpt = c.HasOption("cdre", "data_usage_multiply_factor"); hasOpt {
- cfg.CdreDefaultInstance.DataUsageMultiplyFactor, _ = c.GetFloat64("cdre", "data_usage_multiply_factor")
- }
- if hasOpt = c.HasOption("cdre", "cost_multiply_factor"); hasOpt {
- cfg.CdreDefaultInstance.CostMultiplyFactor, _ = c.GetFloat64("cdre", "cost_multiply_factor")
- }
- if hasOpt = c.HasOption("cdre", "cost_rounding_decimals"); hasOpt {
- cfg.CdreDefaultInstance.CostRoundingDecimals, _ = c.GetInt("cdre", "cost_rounding_decimals")
- }
- if hasOpt = c.HasOption("cdre", "cost_shift_digits"); hasOpt {
- cfg.CdreDefaultInstance.CostShiftDigits, _ = c.GetInt("cdre", "cost_shift_digits")
- }
- if hasOpt = c.HasOption("cdre", "export_template"); hasOpt { // Load configs for csv normally from template, fixed_width from xml file
- exportTemplate, _ := c.GetString("cdre", "export_template")
- if strings.HasPrefix(exportTemplate, utils.XML_PROFILE_PREFIX) {
- if xmlTemplates := cfg.XmlCfgDocument.GetCdreCfgs(exportTemplate[len(utils.XML_PROFILE_PREFIX):]); xmlTemplates != nil {
- if cfg.CdreDefaultInstance, err = NewCdreConfigFromXmlCdreCfg(xmlTemplates[exportTemplate[len(utils.XML_PROFILE_PREFIX):]]); err != nil {
- return nil, err
+ if jsnCdreCfg != nil {
+ if self.CdreProfiles == nil {
+ self.CdreProfiles = make(map[string]*CdreConfig)
+ }
+ for profileName, jsnCdre1Cfg := range jsnCdreCfg {
+ if _, hasProfile := self.CdreProfiles[profileName]; !hasProfile { // New profile, create before loading from json
+ self.CdreProfiles[profileName] = new(CdreConfig)
+ if profileName != utils.META_DEFAULT {
+ self.CdreProfiles[profileName] = self.CdreProfiles[utils.META_DEFAULT] // Load defaults into newly initialized config
}
}
- } else { // Not loading out of template
- if flds, err := NewCfgCdrFieldsFromIds(cfg.CdreDefaultInstance.CdrFormat == utils.CDRE_FIXED_WIDTH,
- strings.Split(exportTemplate, string(utils.CSV_SEP))...); err != nil {
- return nil, err
- } else {
- cfg.CdreDefaultInstance.ContentFields = flds
+ if err = self.CdreProfiles[profileName].loadFromJsonCfg(jsnCdre1Cfg); err != nil { // Update the existing profile with content from json config
+ return err
}
}
}
- if hasOpt = c.HasOption("cdre", "export_dir"); hasOpt {
- cfg.CdreDefaultInstance.ExportDir, _ = c.GetString("cdre", "export_dir")
- }
- // CDRC Default instance parsing
- if cdrcFileCfgInst, err := NewCdrcConfigFromFileParams(c); err != nil {
- return nil, err
- } else {
- cfg.CdrcInstances = []*CdrcConfig{cdrcFileCfgInst}
- }
- if cfg.XmlCfgDocument != nil { // Add the possible configured instances inside xml doc
- for id, xmlCdrcCfg := range cfg.XmlCfgDocument.GetCdrcCfgs("") {
- if cdrcInst, err := NewCdrcConfigFromCgrXmlCdrcCfg(id, xmlCdrcCfg); err != nil {
- return nil, err
- } else {
- cfg.CdrcInstances = append(cfg.CdrcInstances, cdrcInst)
+ if jsnCdrcCfg != nil {
+ if self.CdrcProfiles == nil {
+ self.CdrcProfiles = make(map[string]*CdrcConfig)
+ }
+ for profileName, jsnCrc1Cfg := range jsnCdrcCfg {
+ if _, hasProfile := self.CdrcProfiles[profileName]; !hasProfile {
+ self.CdrcProfiles[profileName] = new(CdrcConfig)
+ if profileName != utils.META_DEFAULT {
+ self.CdrcProfiles[profileName] = self.CdrcProfiles[utils.META_DEFAULT] // Load defaults into newly initialized config
+ }
+ }
+ if err = self.CdrcProfiles[profileName].loadFromJsonCfg(jsnCrc1Cfg); err != nil {
+ return err
}
}
}
- if hasOpt = c.HasOption("mediator", "enabled"); hasOpt {
- cfg.MediatorEnabled, _ = c.GetBool("mediator", "enabled")
- }
- if hasOpt = c.HasOption("mediator", "rater"); hasOpt {
- cfg.MediatorRater, _ = c.GetString("mediator", "rater")
- }
- if hasOpt = c.HasOption("mediator", "reconnects"); hasOpt {
- cfg.MediatorReconnects, _ = c.GetInt("mediator", "reconnects")
- }
- if hasOpt = c.HasOption("mediator", "cdrstats"); hasOpt {
- cfg.MediatorStats, _ = c.GetString("mediator", "cdrstats")
- }
- if hasOpt = c.HasOption("mediator", "store_disable"); hasOpt {
- cfg.MediatorStoreDisable, _ = c.GetBool("mediator", "store_disable")
- }
- if hasOpt = c.HasOption("session_manager", "enabled"); hasOpt {
- cfg.SMEnabled, _ = c.GetBool("session_manager", "enabled")
- }
- if hasOpt = c.HasOption("session_manager", "switch_type"); hasOpt {
- cfg.SMSwitchType, _ = c.GetString("session_manager", "switch_type")
- }
- if hasOpt = c.HasOption("session_manager", "rater"); hasOpt {
- cfg.SMRater, _ = c.GetString("session_manager", "rater")
- }
- if hasOpt = c.HasOption("session_manager", "cdrs"); hasOpt {
- cfg.SMCdrS, _ = c.GetString("session_manager", "cdrs")
- }
- if hasOpt = c.HasOption("session_manager", "reconnects"); hasOpt {
- cfg.SMReconnects, _ = c.GetInt("session_manager", "reconnects")
- }
- if hasOpt = c.HasOption("session_manager", "debit_interval"); hasOpt {
- cfg.SMDebitInterval, _ = c.GetInt("session_manager", "debit_interval")
- }
- if hasOpt = c.HasOption("session_manager", "min_call_duration"); hasOpt {
- minCallDurStr, _ := c.GetString("session_manager", "min_call_duration")
- if cfg.SMMinCallDuration, err = utils.ParseDurationWithSecs(minCallDurStr); err != nil {
- return nil, err
+ if jsnSMCfg != nil {
+ if jsnSMCfg.Enabled != nil {
+ self.SMEnabled = *jsnSMCfg.Enabled
+ }
+ if jsnSMCfg.Switch_type != nil {
+ self.SMSwitchType = *jsnSMCfg.Switch_type
+ }
+ if jsnSMCfg.Rater != nil {
+ self.SMRater = *jsnSMCfg.Rater
+ }
+ if jsnSMCfg.Cdrs != nil {
+ self.SMCdrS = *jsnSMCfg.Cdrs
+ }
+ if jsnSMCfg.Reconnects != nil {
+ self.SMReconnects = *jsnSMCfg.Reconnects
+ }
+ if jsnSMCfg.Debit_interval != nil {
+ self.SMDebitInterval = *jsnSMCfg.Debit_interval
+ }
+ if jsnSMCfg.Max_call_duration != nil {
+ if self.SMMaxCallDuration, err = utils.ParseDurationWithSecs(*jsnSMCfg.Max_call_duration); err != nil {
+ return err
+ }
+ }
+ if jsnSMCfg.Min_call_duration != nil {
+ if self.SMMinCallDuration, err = utils.ParseDurationWithSecs(*jsnSMCfg.Min_call_duration); err != nil {
+ return err
+ }
}
}
- if hasOpt = c.HasOption("session_manager", "max_call_duration"); hasOpt {
- maxCallDurStr, _ := c.GetString("session_manager", "max_call_duration")
- if cfg.SMMaxCallDuration, err = utils.ParseDurationWithSecs(maxCallDurStr); err != nil {
- return nil, err
+ if jsnMediatorCfg != nil {
+ if jsnMediatorCfg.Enabled != nil {
+ self.MediatorEnabled = *jsnMediatorCfg.Enabled
+ }
+ if jsnMediatorCfg.Reconnects != nil {
+ self.MediatorReconnects = *jsnMediatorCfg.Reconnects
+ }
+ if jsnMediatorCfg.Rater != nil {
+ self.MediatorRater = *jsnMediatorCfg.Rater
+ }
+ if jsnMediatorCfg.Cdrstats != nil {
+ self.MediatorStats = *jsnMediatorCfg.Cdrstats
+ }
+ if jsnMediatorCfg.Store_disable != nil {
+ self.MediatorStoreDisable = *jsnMediatorCfg.Store_disable
}
}
- if hasOpt = c.HasOption("freeswitch", "server"); hasOpt {
- cfg.FreeswitchServer, _ = c.GetString("freeswitch", "server")
- }
- if hasOpt = c.HasOption("freeswitch", "passwd"); hasOpt {
- cfg.FreeswitchPass, _ = c.GetString("freeswitch", "passwd")
- }
- if hasOpt = c.HasOption("freeswitch", "reconnects"); hasOpt {
- cfg.FreeswitchReconnects, _ = c.GetInt("freeswitch", "reconnects")
- }
- if hasOpt = c.HasOption("freeswitch", "min_dur_low_balance"); hasOpt {
- minDurStr, _ := c.GetString("freeswitch", "min_dur_low_balance")
- if cfg.FSMinDurLowBalance, err = utils.ParseDurationWithSecs(minDurStr); err != nil {
- return nil, err
+ if jsnFSCfg != nil {
+ if jsnFSCfg.Server != nil {
+ self.FreeswitchServer = *jsnFSCfg.Server
+ }
+ if jsnFSCfg.Password != nil {
+ self.FreeswitchPass = *jsnFSCfg.Password
+ }
+ if jsnFSCfg.Reconnects != nil {
+ self.FreeswitchReconnects = *jsnFSCfg.Reconnects
+ }
+ if jsnFSCfg.Min_dur_low_balance != nil {
+ if self.FSMinDurLowBalance, err = utils.ParseDurationWithSecs(*jsnFSCfg.Min_dur_low_balance); err != nil {
+ return err
+ }
+ }
+ if jsnFSCfg.Low_balance_ann_file != nil {
+ self.FSLowBalanceAnnFile = *jsnFSCfg.Low_balance_ann_file
+ }
+ if jsnFSCfg.Empty_balance_context != nil {
+ self.FSEmptyBalanceContext = *jsnFSCfg.Empty_balance_context
+ }
+ if jsnFSCfg.Empty_balance_ann_file != nil {
+ self.FSEmptyBalanceAnnFile = *jsnFSCfg.Empty_balance_ann_file
+ }
+ if jsnFSCfg.Cdr_extra_fields != nil {
+ if self.FSCdrExtraFields, err = utils.ParseRSRFieldsFromSlice(*jsnFSCfg.Cdr_extra_fields); err != nil {
+ return err
+ }
}
}
- if hasOpt = c.HasOption("freeswitch", "low_balance_ann_file"); hasOpt {
- cfg.FSLowBalanceAnnFile, _ = c.GetString("freeswitch", "low_balance_ann_file")
- }
- if hasOpt = c.HasOption("freeswitch", "empty_balance_context"); hasOpt {
- cfg.FSEmptyBalanceContext, _ = c.GetString("freeswitch", "empty_balance_context")
- }
- if hasOpt = c.HasOption("freeswitch", "empty_balance_ann_file"); hasOpt {
- cfg.FSEmptyBalanceAnnFile, _ = c.GetString("freeswitch", "empty_balance_ann_file")
- }
- if hasOpt = c.HasOption("freeswitch", "cdr_extra_fields"); hasOpt {
- extraFieldsStr, _ := c.GetString("freeswitch", "cdr_extra_fields")
- if extraFields, err := utils.ParseRSRFields(extraFieldsStr, utils.FIELDS_SEP); err != nil {
- return nil, err
- } else {
- cfg.FSCdrExtraFields = extraFields
+ if jsnOsipsCfg != nil {
+ if jsnOsipsCfg.Listen_udp != nil {
+ self.OsipsListenUdp = *jsnOsipsCfg.Listen_udp
+ }
+ if jsnOsipsCfg.Mi_addr != nil {
+ self.OsipsMiAddr = *jsnOsipsCfg.Mi_addr
+ }
+ if jsnOsipsCfg.Events_subscribe_interval != nil {
+ if self.OsipsEvSubscInterval, err = utils.ParseDurationWithSecs(*jsnOsipsCfg.Events_subscribe_interval); err != nil {
+ return err
+ }
+ }
+ if jsnOsipsCfg.Reconnects != nil {
+ self.OsipsReconnects = *jsnOsipsCfg.Reconnects
}
}
- if hasOpt = c.HasOption("opensips", "listen_udp"); hasOpt {
- cfg.OsipsListenUdp, _ = c.GetString("opensips", "listen_udp")
- }
- if hasOpt = c.HasOption("opensips", "mi_addr"); hasOpt {
- cfg.OsipsMiAddr, _ = c.GetString("opensips", "mi_addr")
- }
- if hasOpt = c.HasOption("opensips", "events_subscribe_interval"); hasOpt {
- evSubscIntervalStr, _ := c.GetString("opensips", "events_subscribe_interval")
- if cfg.OsipsEvSubscInterval, err = utils.ParseDurationWithSecs(evSubscIntervalStr); err != nil {
- return nil, err
+ if jsnKamCfg != nil {
+ if jsnKamCfg.Evapi_addr != nil {
+ self.KamailioEvApiAddr = *jsnKamCfg.Evapi_addr
+ }
+ if jsnKamCfg.Reconnects != nil {
+ self.KamailioReconnects = *jsnKamCfg.Reconnects
}
}
- if hasOpt = c.HasOption("opensips", "reconnects"); hasOpt {
- cfg.OsipsReconnects, _ = c.GetInt("opensips", "reconnects")
- }
- if hasOpt = c.HasOption("kamailio", "evapi_addr"); hasOpt {
- cfg.KamailioEvApiAddr, _ = c.GetString("kamailio", "evapi_addr")
- }
- if hasOpt = c.HasOption("kamailio", "reconnects"); hasOpt {
- cfg.KamailioReconnects, _ = c.GetInt("kamailio", "reconnects")
- }
- if cfg.DerivedChargers, err = ParseCfgDerivedCharging(c); err != nil {
- return nil, err
- }
- if hasOpt = c.HasOption("derived_charging", "combined_chargers"); hasOpt {
- cfg.CombinedDerivedChargers, _ = c.GetBool("derived_charging", "combined_chargers")
- }
- if hasOpt = c.HasOption("history_agent", "enabled"); hasOpt {
- cfg.HistoryAgentEnabled, _ = c.GetBool("history_agent", "enabled")
- }
- if hasOpt = c.HasOption("history_agent", "server"); hasOpt {
- cfg.HistoryServer, _ = c.GetString("history_agent", "server")
- }
- if hasOpt = c.HasOption("history_server", "enabled"); hasOpt {
- cfg.HistoryServerEnabled, _ = c.GetBool("history_server", "enabled")
- }
- if hasOpt = c.HasOption("history_server", "history_dir"); hasOpt {
- cfg.HistoryDir, _ = c.GetString("history_server", "history_dir")
- }
- if hasOpt = c.HasOption("history_server", "save_interval"); hasOpt {
- saveIntvlStr, _ := c.GetString("history_server", "save_interval")
- if cfg.HistorySaveInterval, err = utils.ParseDurationWithSecs(saveIntvlStr); err != nil {
- return nil, err
+ if jsnHistAgentCfg != nil {
+ if jsnHistAgentCfg.Enabled != nil {
+ self.HistoryAgentEnabled = *jsnHistAgentCfg.Enabled
+ }
+ if jsnHistAgentCfg.Server != nil {
+ self.HistoryServer = *jsnHistAgentCfg.Server
}
}
- if hasOpt = c.HasOption("mailer", "server"); hasOpt {
- cfg.MailerServer, _ = c.GetString("mailer", "server")
+ if jsnHistServCfg != nil {
+ if jsnHistServCfg.Enabled != nil {
+ self.HistoryServerEnabled = *jsnHistServCfg.Enabled
+ }
+ if jsnHistServCfg.History_dir != nil {
+ self.HistoryDir = *jsnHistServCfg.History_dir
+ }
+ if jsnHistServCfg.Save_interval != nil {
+ if self.HistorySaveInterval, err = utils.ParseDurationWithSecs(*jsnHistServCfg.Save_interval); err != nil {
+ return err
+ }
+ }
}
- if hasOpt = c.HasOption("mailer", "auth_user"); hasOpt {
- cfg.MailerAuthUser, _ = c.GetString("mailer", "auth_user")
+ if jsnMailerCfg != nil {
+ if jsnMailerCfg.Server != nil {
+ self.MailerServer = *jsnMailerCfg.Server
+ }
+ if jsnMailerCfg.Auth_user != nil {
+ self.MailerAuthUser = *jsnMailerCfg.Auth_user
+ }
+ if jsnMailerCfg.Auth_passwd != nil {
+ self.MailerAuthPass = *jsnMailerCfg.Auth_passwd
+ }
+ if jsnMailerCfg.From_address != nil {
+ self.MailerFromAddr = *jsnMailerCfg.From_address
+ }
}
- if hasOpt = c.HasOption("mailer", "auth_passwd"); hasOpt {
- cfg.MailerAuthPass, _ = c.GetString("mailer", "auth_passwd")
- }
- if hasOpt = c.HasOption("mailer", "from_address"); hasOpt {
- cfg.MailerFromAddr, _ = c.GetString("mailer", "from_address")
- }
- return cfg, nil
+ return nil
}
diff --git a/config/cgrates_cfg_defaults.json b/config/config_defaults.go
similarity index 74%
rename from config/cgrates_cfg_defaults.json
rename to config/config_defaults.go
index 876824d85..2985b3ea1 100644
--- a/config/cgrates_cfg_defaults.json
+++ b/config/config_defaults.go
@@ -1,3 +1,24 @@
+/*
+Real-time Charging System 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
+
+const CGRATES_CFG_JSON = `
{
// Real-time Charging System for Telecom & ISP environments
@@ -111,13 +132,14 @@
"mediation_run_ids": [], // filter on CDR MediationRunId fields
"rated_accounts": [], // filter on CDR RatedAccount fields
"rated_subjects": [], // filter on CDR RatedSubject fields
- "cost_intervals": [], // filter on CDR Cost
+ "cost_interval": [], // filter on CDR Cost
},
"cdre": {
- "CDRE-FW1": {
+ "*default": {
"cdr_format": "csv", // exported CDRs format
+ "field_separator": ",",
"data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes)
"cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
"cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding
@@ -127,21 +149,21 @@
"export_dir": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed
"header_fields": [], // template of the exported header fields
"content_fields": [ // template of the exported content fields
- {"tag": "CgrId", "type": "cdrfield", "value": "cgrid", "width": 40, "mandatory": true},
- {"tag":"RunId", "type": "cdrfield", "value": "mediation_runid", "width": 20},
- {"tag":"Tor", "type": "cdrfield", "value": "tor", "width": 6},
- {"tag":"AccId", "type": "cdrfield", "value": "accid", "width": 36},
- {"tag":"ReqType", "type": "cdrfield", "value": "reqtype", "width": 13},
- {"tag":"Direction", "type": "cdrfield", "value": "direction", "width": 4},
- {"tag":"Tenant", "type": "cdrfield", "value": "tenant", "width": 24},
- {"tag":"Category", "type": "cdrfield", "value": "category", "width": 10},
- {"tag":"Account", "type": "cdrfield", "value": "account", "width": 24},
- {"tag":"Subject", "type": "cdrfield", "value": "subject", "width": 24},
- {"tag":"Destination", "type": "cdrfield", "value": "destination", "width": 24},
- {"tag":"SetupTime", "type": "cdrfield", "value": "setup_time", "layout": "2006-01-02T15:04:05Z07:00", "width": 30},
- {"tag":"AnswerTime", "type": "cdrfield", "value": "answer_time", "layout": "2006-01-02T15:04:05Z07:00", "width": 30},
- {"tag":"Usage", "type": "cdrfield", "value": "usage", "width": 30},
- {"tag":"Cost", "type": "cdrfield", "value": "cost", "width": 24},
+ {"tag": "CgrId", "cdr_field_id": "cgrid", "type": "cdrfield", "value": "cgrid"},
+ {"tag":"RunId", "cdr_field_id": "mediation_runid", "type": "cdrfield", "value": "mediation_runid"},
+ {"tag":"Tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "tor"},
+ {"tag":"AccId", "cdr_field_id": "accid", "type": "cdrfield", "value": "accid"},
+ {"tag":"ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "reqtype"},
+ {"tag":"Direction", "cdr_field_id": "direction", "type": "cdrfield", "value": "direction"},
+ {"tag":"Tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "tenant"},
+ {"tag":"Category", "cdr_field_id": "category", "type": "cdrfield", "value": "category"},
+ {"tag":"Account", "cdr_field_id": "account", "type": "cdrfield", "value": "account"},
+ {"tag":"Subject", "cdr_field_id": "subject", "type": "cdrfield", "value": "subject"},
+ {"tag":"Destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "destination"},
+ {"tag":"SetupTime", "cdr_field_id": "setup_time", "type": "cdrfield", "value": "setup_time", "layout": "2006-01-02T15:04:05Z07:00"},
+ {"tag":"AnswerTime", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "answer_time", "layout": "2006-01-02T15:04:05Z07:00"},
+ {"tag":"Usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "usage"},
+ {"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"},
],
"trailer_fields": [], // template of the exported trailer fields
}
@@ -149,7 +171,7 @@
"cdrc": {
- "instance1": {
+ "*default": {
"enabled": false, // enable CDR client functionality
"cdrs_address": "internal", // address where to reach CDR server.
"cdr_format": "csv", // CDR file format
@@ -160,19 +182,18 @@
"cdr_out_dir": "/var/log/cgrates/cdrc/out", // absolute path towards the directory where processed CDRs will be moved
"cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database
"cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
- {"tag": "accid", "value": "0;13"},
- {"tag": "reqtype", "value": "1"},
- {"tag": "direction", "value": "2"},
- {"tag": "tenant", "value": "3"},
- {"tag": "category", "value": "4"},
- {"tag": "account", "value": "5"},
- {"tag": "subject", "value": "6"},
- {"tag": "destination", "value": "7"},
- {"tag": "setup_time", "value": "8"},
- {"tag": "answer_time", "value": "9"},
- {"tag": "usage", "value": "10"},
- {"tag": "extr1", "value": "11"},
- {"tag": "extr2", "value": "12"},
+ {"tag": "tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "2", "mandatory": true},
+ {"tag": "accid", "cdr_field_id": "accid", "type": "cdrfield", "value": "3", "mandatory": true},
+ {"tag": "reqtype", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "4", "mandatory": true},
+ {"tag": "direction", "cdr_field_id": "direction", "type": "cdrfield", "value": "5", "mandatory": true},
+ {"tag": "tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "6", "mandatory": true},
+ {"tag": "category", "cdr_field_id": "category", "type": "cdrfield", "value": "7", "mandatory": true},
+ {"tag": "account", "cdr_field_id": "account", "type": "cdrfield", "value": "8", "mandatory": true},
+ {"tag": "subject", "cdr_field_id": "subject", "type": "cdrfield", "value": "9", "mandatory": true},
+ {"tag": "destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "10", "mandatory": true},
+ {"tag": "setup_time", "cdr_field_id": "setup_time", "type": "cdrfield", "value": "11", "mandatory": true},
+ {"tag": "answer_time", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "12", "mandatory": true},
+ {"tag": "usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "13", "mandatory": true},
],
}
},
@@ -236,4 +257,4 @@
"from_address": "cgr-mailer@localhost.localdomain" // from address used when sending emails out
},
-}
\ No newline at end of file
+}`
diff --git a/config/config_json.go b/config/config_json.go
index 189a987f9..003108664 100644
--- a/config/config_json.go
+++ b/config/config_json.go
@@ -49,23 +49,24 @@ const (
)
// Loads the json config out of io.Reader, eg other sources than file, maybe over http
-func NewCgrJsonCfg(r io.Reader) (CgrJsonCfg, error) {
+func NewCgrJsonCfgFromReader(r io.Reader) (*CgrJsonCfg, error) {
var cgrJsonCfg CgrJsonCfg
jr := JsonConfigReader.New(r)
if err := json.NewDecoder(jr).Decode(&cgrJsonCfg); err != nil {
return nil, err
}
- return cgrJsonCfg, nil
+ return &cgrJsonCfg, nil
}
// Loads the config out of file
-func NewCgrJsonCfgFromFile(fpath string) (CgrJsonCfg, error) {
+func NewCgrJsonCfgFromFile(fpath string) (*CgrJsonCfg, error) {
cfgFile, err := os.Open(fpath)
if err != nil {
return nil, err
}
defer cfgFile.Close()
- return NewCgrJsonCfg(cfgFile)
+
+ return NewCgrJsonCfgFromReader(cfgFile)
}
// Main object holding the loaded config as section raw messages
diff --git a/config/config_json_test.go b/config/config_json_test.go
index 4f4722c43..f93dfdffe 100644
--- a/config/config_json_test.go
+++ b/config/config_json_test.go
@@ -21,19 +21,21 @@ package config
import (
"github.com/cgrates/cgrates/utils"
"reflect"
+ "strings"
"testing"
)
-var cgrJsonCfg CgrJsonCfg
+var dfCgrJsonCfg *CgrJsonCfg
-func TestNewCgrJsonCfgFromFile(t *testing.T) {
+// Loads up the default configuration and tests it's sections one by one
+func TestDfNewdfCgrJsonCfgFromReader(t *testing.T) {
var err error
- if cgrJsonCfg, err = NewCgrJsonCfgFromFile("cgrates_cfg_defaults.json"); err != nil {
- t.Error(err.Error())
+ if dfCgrJsonCfg, err = NewCgrJsonCfgFromReader(strings.NewReader(CGRATES_CFG_JSON)); err != nil {
+ t.Error(err)
}
}
-func TestGeneralJsonCfg(t *testing.T) {
+func TestDfGeneralJsonCfg(t *testing.T) {
eCfg := &GeneralJsonCfg{
Http_skip_tls_veify: utils.BoolPointer(false),
Rounding_decimals: utils.IntPointer(10),
@@ -43,26 +45,26 @@ func TestGeneralJsonCfg(t *testing.T) {
Default_category: utils.StringPointer("call"),
Default_tenant: utils.StringPointer("cgrates.org"),
Default_subject: utils.StringPointer("cgrates")}
- if gCfg, err := cgrJsonCfg.GeneralJsonCfg(); err != nil {
+ if gCfg, err := dfCgrJsonCfg.GeneralJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, gCfg) {
t.Error("Received: ", gCfg)
}
}
-func TestListenJsonCfg(t *testing.T) {
+func TestDfListenJsonCfg(t *testing.T) {
eCfg := &ListenJsonCfg{
Rpc_json: utils.StringPointer("127.0.0.1:2012"),
Rpc_gob: utils.StringPointer("127.0.0.1:2013"),
Http: utils.StringPointer("127.0.0.1:2080")}
- if cfg, err := cgrJsonCfg.ListenJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.ListenJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestDbJsonCfg(t *testing.T) {
+func TestDfDbJsonCfg(t *testing.T) {
eCfg := &DbJsonCfg{
Db_type: utils.StringPointer("redis"),
Db_host: utils.StringPointer("127.0.0.1"),
@@ -71,7 +73,7 @@ func TestDbJsonCfg(t *testing.T) {
Db_user: utils.StringPointer(""),
Db_passwd: utils.StringPointer(""),
}
- if cfg, err := cgrJsonCfg.DbJsonCfg(RATINGDB_JSN); err != nil {
+ if cfg, err := dfCgrJsonCfg.DbJsonCfg(RATINGDB_JSN); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
@@ -84,7 +86,7 @@ func TestDbJsonCfg(t *testing.T) {
Db_user: utils.StringPointer(""),
Db_passwd: utils.StringPointer(""),
}
- if cfg, err := cgrJsonCfg.DbJsonCfg(ACCOUNTINGDB_JSN); err != nil {
+ if cfg, err := dfCgrJsonCfg.DbJsonCfg(ACCOUNTINGDB_JSN); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
@@ -99,41 +101,41 @@ func TestDbJsonCfg(t *testing.T) {
Max_open_conns: utils.IntPointer(0),
Max_idle_conns: utils.IntPointer(-1),
}
- if cfg, err := cgrJsonCfg.DbJsonCfg(STORDB_JSN); err != nil {
+ if cfg, err := dfCgrJsonCfg.DbJsonCfg(STORDB_JSN); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestBalancerJsonCfg(t *testing.T) {
+func TestDfBalancerJsonCfg(t *testing.T) {
eCfg := &BalancerJsonCfg{Enabled: utils.BoolPointer(false)}
- if cfg, err := cgrJsonCfg.BalancerJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.BalancerJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestRaterJsonCfg(t *testing.T) {
+func TestDfRaterJsonCfg(t *testing.T) {
eCfg := &RaterJsonCfg{Enabled: utils.BoolPointer(false), Balancer: utils.StringPointer("")}
- if cfg, err := cgrJsonCfg.RaterJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.RaterJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestSchedulerJsonCfg(t *testing.T) {
+func TestDfSchedulerJsonCfg(t *testing.T) {
eCfg := &SchedulerJsonCfg{Enabled: utils.BoolPointer(false)}
- if cfg, err := cgrJsonCfg.SchedulerJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.SchedulerJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestCdrsJsonCfg(t *testing.T) {
+func TestDfCdrsJsonCfg(t *testing.T) {
eCfg := &CdrsJsonCfg{
Enabled: utils.BoolPointer(false),
Extra_fields: utils.StringSlicePointer([]string{}),
@@ -141,14 +143,14 @@ func TestCdrsJsonCfg(t *testing.T) {
Cdrstats: utils.StringPointer(""),
Store_disable: utils.BoolPointer(false),
}
- if cfg, err := cgrJsonCfg.CdrsJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.CdrsJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestMediatorJsonCfg(t *testing.T) {
+func TestDfMediatorJsonCfg(t *testing.T) {
eCfg := &MediatorJsonCfg{
Enabled: utils.BoolPointer(false),
Reconnects: utils.IntPointer(3),
@@ -156,14 +158,14 @@ func TestMediatorJsonCfg(t *testing.T) {
Cdrstats: utils.StringPointer(""),
Store_disable: utils.BoolPointer(false),
}
- if cfg, err := cgrJsonCfg.MediatorJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.MediatorJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestCdrStatsJsonCfg(t *testing.T) {
+func TestDfCdrStatsJsonCfg(t *testing.T) {
eCfg := &CdrStatsJsonCfg{
Enabled: utils.BoolPointer(false),
Queue_length: utils.IntPointer(50),
@@ -184,85 +186,85 @@ func TestCdrStatsJsonCfg(t *testing.T) {
Mediation_run_ids: utils.StringSlicePointer([]string{}),
Rated_accounts: utils.StringSlicePointer([]string{}),
Rated_subjects: utils.StringSlicePointer([]string{}),
- Cost_intervals: utils.StringSlicePointer([]string{}),
+ Cost_interval: utils.Float64SlicePointer([]float64{}),
}
- if cfg, err := cgrJsonCfg.CdrStatsJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.CdrStatsJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestCdreJsonCfgs(t *testing.T) {
+func TestDfCdreJsonCfgs(t *testing.T) {
eFields := []*CdrFieldJsonCfg{}
eContentFlds := []*CdrFieldJsonCfg{
&CdrFieldJsonCfg{Tag: utils.StringPointer("CgrId"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("cgrid"),
- Width: utils.IntPointer(40),
- Mandatory: utils.BoolPointer(true)},
+ Cdr_field_id: utils.StringPointer("cgrid"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("cgrid")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("RunId"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("mediation_runid"),
- Width: utils.IntPointer(20)},
+ Cdr_field_id: utils.StringPointer("mediation_runid"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("mediation_runid")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Tor"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("tor"),
- Width: utils.IntPointer(6)},
+ Cdr_field_id: utils.StringPointer("tor"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("tor")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("AccId"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("accid"),
- Width: utils.IntPointer(36)},
+ Cdr_field_id: utils.StringPointer("accid"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("accid")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("ReqType"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("reqtype"),
- Width: utils.IntPointer(13)},
+ Cdr_field_id: utils.StringPointer("reqtype"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("reqtype")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Direction"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("direction"),
- Width: utils.IntPointer(4)},
+ Cdr_field_id: utils.StringPointer("direction"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("direction")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Tenant"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("tenant"),
- Width: utils.IntPointer(24)},
+ Cdr_field_id: utils.StringPointer("tenant"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("tenant")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Category"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("category"),
- Width: utils.IntPointer(10)},
+ Cdr_field_id: utils.StringPointer("category"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("category")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Account"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("account"),
- Width: utils.IntPointer(24)},
+ Cdr_field_id: utils.StringPointer("account"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("account")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Subject"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("subject"),
- Width: utils.IntPointer(24)},
+ Cdr_field_id: utils.StringPointer("subject"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("subject")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Destination"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("destination"),
- Width: utils.IntPointer(24)},
+ Cdr_field_id: utils.StringPointer("destination"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("destination")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("SetupTime"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("setup_time"),
- Width: utils.IntPointer(30),
- Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")},
+ Cdr_field_id: utils.StringPointer("setup_time"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("setup_time"),
+ Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("AnswerTime"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("answer_time"),
- Width: utils.IntPointer(30),
- Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")},
+ Cdr_field_id: utils.StringPointer("answer_time"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("answer_time"),
+ Layout: utils.StringPointer("2006-01-02T15:04:05Z07:00")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Usage"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("usage"),
- Width: utils.IntPointer(30)},
+ Cdr_field_id: utils.StringPointer("usage"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("usage")},
&CdrFieldJsonCfg{Tag: utils.StringPointer("Cost"),
- Type: utils.StringPointer("cdrfield"),
- Value: utils.StringPointer("cost"),
- Width: utils.IntPointer(24)},
+ Cdr_field_id: utils.StringPointer("cost"),
+ Type: utils.StringPointer("cdrfield"),
+ Value: utils.StringPointer("cost")},
}
eCfg := map[string]*CdreJsonCfg{
- "CDRE-FW1": &CdreJsonCfg{
+ utils.META_DEFAULT: &CdreJsonCfg{
Cdr_format: utils.StringPointer("csv"),
+ Field_separator: utils.StringPointer(","),
Data_usage_multiply_factor: utils.Float64Pointer(1.0),
Cost_multiply_factor: utils.Float64Pointer(1.0),
Cost_rounding_decimals: utils.IntPointer(-1),
@@ -275,31 +277,42 @@ func TestCdreJsonCfgs(t *testing.T) {
Trailer_fields: &eFields,
},
}
- if cfg, err := cgrJsonCfg.CdreJsonCfgs(); err != nil {
+ if cfg, err := dfCgrJsonCfg.CdreJsonCfgs(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestCdrcJsonCfg(t *testing.T) {
+func TestDfCdrcJsonCfg(t *testing.T) {
cdrFields := []*CdrFieldJsonCfg{
- &CdrFieldJsonCfg{Tag: utils.StringPointer("accid"), Value: utils.StringPointer("0;13")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("reqtype"), Value: utils.StringPointer("1")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("direction"), Value: utils.StringPointer("2")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("tenant"), Value: utils.StringPointer("3")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("category"), Value: utils.StringPointer("4")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("account"), Value: utils.StringPointer("5")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("subject"), Value: utils.StringPointer("6")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("destination"), Value: utils.StringPointer("7")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("setup_time"), Value: utils.StringPointer("8")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("answer_time"), Value: utils.StringPointer("9")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("usage"), Value: utils.StringPointer("10")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("extr1"), Value: utils.StringPointer("11")},
- &CdrFieldJsonCfg{Tag: utils.StringPointer("extr2"), Value: utils.StringPointer("12")},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("tor"), Cdr_field_id: utils.StringPointer("tor"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("2"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("accid"), Cdr_field_id: utils.StringPointer("accid"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("3"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("reqtype"), Cdr_field_id: utils.StringPointer("reqtype"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("4"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("direction"), Cdr_field_id: utils.StringPointer("direction"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("5"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("tenant"), Cdr_field_id: utils.StringPointer("tenant"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("6"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("category"), Cdr_field_id: utils.StringPointer("category"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("7"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("account"), Cdr_field_id: utils.StringPointer("account"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("8"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("subject"), Cdr_field_id: utils.StringPointer("subject"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("9"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("destination"), Cdr_field_id: utils.StringPointer("destination"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("10"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("setup_time"), Cdr_field_id: utils.StringPointer("setup_time"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("11"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("answer_time"), Cdr_field_id: utils.StringPointer("answer_time"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("12"), Mandatory: utils.BoolPointer(true)},
+ &CdrFieldJsonCfg{Tag: utils.StringPointer("usage"), Cdr_field_id: utils.StringPointer("usage"), Type: utils.StringPointer(utils.CDRFIELD),
+ Value: utils.StringPointer("13"), Mandatory: utils.BoolPointer(true)},
}
eCfg := map[string]*CdrcJsonCfg{
- "instance1": &CdrcJsonCfg{
+ "*default": &CdrcJsonCfg{
Enabled: utils.BoolPointer(false),
Cdrs_address: utils.StringPointer("internal"),
Cdr_format: utils.StringPointer("csv"),
@@ -312,14 +325,14 @@ func TestCdrcJsonCfg(t *testing.T) {
Cdr_fields: &cdrFields,
},
}
- if cfg, err := cgrJsonCfg.CdrcJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.CdrcJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestSessionManagerJsonCfg(t *testing.T) {
+func TestDfSessionManagerJsonCfg(t *testing.T) {
eCfg := &SessionManagerJsonCfg{
Enabled: utils.BoolPointer(false),
Switch_type: utils.StringPointer("freeswitch"),
@@ -330,14 +343,14 @@ func TestSessionManagerJsonCfg(t *testing.T) {
Min_call_duration: utils.StringPointer("0s"),
Max_call_duration: utils.StringPointer("3h"),
}
- if cfg, err := cgrJsonCfg.SessionManagerJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.SessionManagerJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestFSJsonCfg(t *testing.T) {
+func TestDfFSJsonCfg(t *testing.T) {
eCfg := &FSJsonCfg{
Server: utils.StringPointer("127.0.0.1:8021"),
Password: utils.StringPointer("ClueCon"),
@@ -348,74 +361,117 @@ func TestFSJsonCfg(t *testing.T) {
Empty_balance_ann_file: utils.StringPointer(""),
Cdr_extra_fields: utils.StringSlicePointer([]string{}),
}
- if cfg, err := cgrJsonCfg.FSJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.FSJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestKamailioJsonCfg(t *testing.T) {
+func TestDfKamailioJsonCfg(t *testing.T) {
eCfg := &KamailioJsonCfg{
Evapi_addr: utils.StringPointer("127.0.0.1:8448"),
Reconnects: utils.IntPointer(3),
}
- if cfg, err := cgrJsonCfg.KamailioJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.KamailioJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestOsipsJsonCfg(t *testing.T) {
+func TestDfOsipsJsonCfg(t *testing.T) {
eCfg := &OsipsJsonCfg{
Listen_udp: utils.StringPointer("127.0.0.1:2020"),
Mi_addr: utils.StringPointer("127.0.0.1:8020"),
Events_subscribe_interval: utils.StringPointer("60s"),
Reconnects: utils.IntPointer(3),
}
- if cfg, err := cgrJsonCfg.OsipsJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.OsipsJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestHistServJsonCfg(t *testing.T) {
+func TestDfHistServJsonCfg(t *testing.T) {
eCfg := &HistServJsonCfg{
Enabled: utils.BoolPointer(false),
History_dir: utils.StringPointer("/var/log/cgrates/history"),
Save_interval: utils.StringPointer("1s"),
}
- if cfg, err := cgrJsonCfg.HistServJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.HistServJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestHistAgentJsonCfg(t *testing.T) {
+func TestDfHistAgentJsonCfg(t *testing.T) {
eCfg := &HistAgentJsonCfg{
Enabled: utils.BoolPointer(false),
Server: utils.StringPointer("internal"),
}
- if cfg, err := cgrJsonCfg.HistAgentJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.HistAgentJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
-func TestMailerJsonCfg(t *testing.T) {
+func TestDfMailerJsonCfg(t *testing.T) {
eCfg := &MailerJsonCfg{
Server: utils.StringPointer("localhost"),
Auth_user: utils.StringPointer("cgrates"),
Auth_passwd: utils.StringPointer("CGRateS.org"),
From_address: utils.StringPointer("cgr-mailer@localhost.localdomain"),
}
- if cfg, err := cgrJsonCfg.MailerJsonCfg(); err != nil {
+ if cfg, err := dfCgrJsonCfg.MailerJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
+
+func TestNewCgrJsonCfgFromFile(t *testing.T) {
+ cgrJsonCfg, err := NewCgrJsonCfgFromFile("cfg_data.json")
+ if err != nil {
+ t.Error(err)
+ }
+ eCfg := &GeneralJsonCfg{Default_reqtype: utils.StringPointer("pseudoprepaid")}
+ if gCfg, err := cgrJsonCfg.GeneralJsonCfg(); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(eCfg, gCfg) {
+ t.Error("Received: ", gCfg)
+ }
+ cdrFields := []*CdrFieldJsonCfg{
+ &CdrFieldJsonCfg{Cdr_field_id: utils.StringPointer("tor"), Value: utils.StringPointer("~7:s/^(voice|data|sms)$/*$1/")},
+ &CdrFieldJsonCfg{Cdr_field_id: utils.StringPointer("answer_time"), Value: utils.StringPointer("1")},
+ &CdrFieldJsonCfg{Cdr_field_id: utils.StringPointer("usage"), Value: utils.StringPointer(`~9:s/^(\d+)$/${1}s/`)},
+ }
+ eCfgCdrc := map[string]*CdrcJsonCfg{
+ "CDRC-CSV1": &CdrcJsonCfg{
+ Enabled: utils.BoolPointer(true),
+ Cdr_in_dir: utils.StringPointer("/tmp/cgrates/cdrc1/in"),
+ Cdr_out_dir: utils.StringPointer("/tmp/cgrates/cdrc1/out"),
+ Cdr_source_id: utils.StringPointer("csv1"),
+ },
+ "CDRC-CSV2": &CdrcJsonCfg{
+ Enabled: utils.BoolPointer(true),
+ Cdr_in_dir: utils.StringPointer("/tmp/cgrates/cdrc2/in"),
+ Cdr_out_dir: utils.StringPointer("/tmp/cgrates/cdrc2/out"),
+ Cdr_source_id: utils.StringPointer("csv2"),
+ Cdr_fields: &cdrFields,
+ },
+ }
+ if cfg, err := cgrJsonCfg.CdrcJsonCfg(); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(eCfgCdrc, cfg) {
+ t.Error("Received: ", cfg)
+ }
+ if cfg, err := cgrJsonCfg.HistAgentJsonCfg(); err != nil {
+ t.Error(err)
+ } else if cfg != nil {
+ t.Error("Received: ", cfg)
+ }
+}
diff --git a/config/config_local_test.go b/config/config_local_test.go
deleted file mode 100644
index 5f5fbd4ba..000000000
--- a/config/config_local_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-Rating system designed to be used in VoIP Carriers World
-Copyright (C) 2012-2014 ITsysCOM
-
-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 (
- "flag"
- "path"
- "testing"
-)
-
-var testLocal = flag.Bool("local", false, "Perform the tests only on local test environment, not by default.") // This flag will be passed here via "go test -local" args
-var dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here")
-
-func TestLoadXmlCfg(t *testing.T) {
- if !*testLocal {
- return
- }
- cfgPath := path.Join(*dataDir, "conf", "samples", "config_local_test.cfg")
- cfg, err := NewCGRConfigFromFile(&cfgPath)
- if err != nil {
- t.Error(err)
- }
- if cfg.XmlCfgDocument == nil {
- t.Error("Did not load the XML Config Document")
- }
- if cdreFWCfg := cfg.XmlCfgDocument.GetCdreCfgs("CDREFW-A"); cdreFWCfg == nil {
- t.Error("Could not retrieve CDRExporter FixedWidth config instance")
- }
-}
diff --git a/config/config_test.go b/config/config_test.go
index 6bac80e34..369fd90e2 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -19,13 +19,8 @@ along with this program. If not, see
package config
import (
- "fmt"
"reflect"
- "regexp"
"testing"
- "time"
-
- "github.com/cgrates/cgrates/utils"
)
func TestConfigSharing(t *testing.T) {
@@ -36,338 +31,3 @@ func TestConfigSharing(t *testing.T) {
t.Errorf("Retrieved %v, Expected %v", cfgReturn, cfg)
}
}
-
-// Make sure defaults did not change by mistake
-func TestDefaults(t *testing.T) {
- cfg := &CGRConfig{}
- errSet := cfg.setDefaults()
- if errSet != nil {
- t.Log(fmt.Sprintf("Coud not set defaults: %s!", errSet.Error()))
- t.FailNow()
- }
- eCfg := &CGRConfig{}
- eCfg.RatingDBType = REDIS
- eCfg.RatingDBHost = "127.0.0.1"
- eCfg.RatingDBPort = "6379"
- eCfg.RatingDBName = "10"
- eCfg.RatingDBUser = ""
- eCfg.RatingDBPass = ""
- eCfg.AccountDBType = REDIS
- eCfg.AccountDBHost = "127.0.0.1"
- eCfg.AccountDBPort = "6379"
- eCfg.AccountDBName = "11"
- eCfg.AccountDBUser = ""
- eCfg.AccountDBPass = ""
- eCfg.StorDBType = utils.MYSQL
- eCfg.StorDBHost = "localhost"
- eCfg.StorDBPort = "3306"
- eCfg.StorDBName = "cgrates"
- eCfg.StorDBUser = "cgrates"
- eCfg.StorDBPass = "CGRateS.org"
- eCfg.StorDBMaxOpenConns = 100
- eCfg.StorDBMaxIdleConns = 10
- eCfg.DBDataEncoding = utils.MSGPACK
- eCfg.RPCJSONListen = "127.0.0.1:2012"
- eCfg.RPCGOBListen = "127.0.0.1:2013"
- eCfg.HTTPListen = "127.0.0.1:2080"
- eCfg.DefaultReqType = utils.RATED
- eCfg.DefaultCategory = "call"
- eCfg.DefaultTenant = "cgrates.org"
- eCfg.DefaultSubject = "cgrates"
- eCfg.RoundingDecimals = 10
- eCfg.HttpSkipTlsVerify = false
- eCfg.TpExportPath = "/var/log/cgrates/tpe"
- eCfg.XmlCfgDocument = nil
- eCfg.RaterEnabled = false
- eCfg.RaterBalancer = ""
- eCfg.BalancerEnabled = false
- eCfg.SchedulerEnabled = false
- eCfg.CdreDefaultInstance = NewDefaultCdreConfig()
- eCfg.CdrcInstances = []*CdrcConfig{NewDefaultCdrcConfig()}
- eCfg.CDRSEnabled = false
- eCfg.CDRSExtraFields = []*utils.RSRField{}
- eCfg.CDRSMediator = ""
- eCfg.CDRSStats = ""
- eCfg.CDRSStoreDisable = false
- eCfg.CDRStatsEnabled = false
- eCfg.CDRStatConfig = &CdrStatsConfig{Id: utils.META_DEFAULT, QueueLength: 50, TimeWindow: time.Duration(1) * time.Hour, Metrics: []string{"ASR", "ACD", "ACC"}}
- eCfg.MediatorEnabled = false
- eCfg.MediatorRater = utils.INTERNAL
- eCfg.MediatorReconnects = 3
- eCfg.MediatorStats = ""
- eCfg.MediatorStoreDisable = false
- eCfg.SMEnabled = false
- eCfg.SMSwitchType = FS
- eCfg.SMRater = utils.INTERNAL
- eCfg.SMCdrS = ""
- eCfg.SMReconnects = 3
- eCfg.SMDebitInterval = 10
- eCfg.SMMinCallDuration = time.Duration(0)
- eCfg.SMMaxCallDuration = time.Duration(3) * time.Hour
- eCfg.FreeswitchServer = "127.0.0.1:8021"
- eCfg.FreeswitchPass = "ClueCon"
- eCfg.FreeswitchReconnects = 5
- eCfg.FSMinDurLowBalance = time.Duration(5) * time.Second
- eCfg.FSLowBalanceAnnFile = ""
- eCfg.FSEmptyBalanceContext = ""
- eCfg.FSEmptyBalanceAnnFile = ""
- eCfg.FSCdrExtraFields = []*utils.RSRField{}
- eCfg.OsipsListenUdp = "127.0.0.1:2020"
- eCfg.OsipsMiAddr = "127.0.0.1:8020"
- eCfg.OsipsEvSubscInterval = time.Duration(60) * time.Second
- eCfg.OsipsReconnects = 3
- eCfg.KamailioEvApiAddr = "127.0.0.1:8448"
- eCfg.KamailioReconnects = 3
- eCfg.DerivedChargers = make(utils.DerivedChargers, 0)
- eCfg.CombinedDerivedChargers = true
- eCfg.HistoryAgentEnabled = false
- eCfg.HistoryServer = utils.INTERNAL
- eCfg.HistoryServerEnabled = false
- eCfg.HistoryDir = "/var/log/cgrates/history"
- eCfg.HistorySaveInterval = time.Duration(1) * time.Second
- eCfg.MailerServer = "localhost:25"
- eCfg.MailerAuthUser = "cgrates"
- eCfg.MailerAuthPass = "CGRateS.org"
- eCfg.MailerFromAddr = "cgr-mailer@localhost.localdomain"
- eCfg.DataFolderPath = "/usr/share/cgrates/"
- if !reflect.DeepEqual(cfg, eCfg) {
- t.Log(eCfg)
- t.Log(cfg)
- t.Error("Defaults different than expected!")
- }
-
-}
-
-func TestSanityCheck(t *testing.T) {
- cfg := &CGRConfig{}
- errSet := cfg.setDefaults()
- if errSet != nil {
- t.Error("Coud not set defaults: ", errSet.Error())
- }
- if err := cfg.checkConfigSanity(); err != nil {
- t.Error("Invalid defaults: ", err)
- }
- cfg = &CGRConfig{}
- cfg.CDRSStats = utils.INTERNAL
- if err := cfg.checkConfigSanity(); err == nil {
- t.Error("Failed detecting improper CDRStats configuration within CDRS")
- }
- cfg = &CGRConfig{}
- cfg.MediatorStats = utils.INTERNAL
- if err := cfg.checkConfigSanity(); err == nil {
- t.Error("Failed detecting improper CDRStats configuration within Mediator")
- }
- cfg = &CGRConfig{}
- cfg.SMCdrS = utils.INTERNAL
- if err := cfg.checkConfigSanity(); err == nil {
- t.Error("Failed detecting improper CDRS configuration within SM")
- }
-}
-
-// Load config from file and make sure we have all set
-func TestConfigFromFile(t *testing.T) {
- cfgPth := "test_data.txt"
- cfg, err := NewCGRConfigFromFile(&cfgPth)
- if err != nil {
- t.Log(fmt.Sprintf("Could not parse config: %s!", err))
- t.FailNow()
- }
- eCfg := &CGRConfig{} // Instance we expect to get out after reading config file
- eCfg.setDefaults()
- eCfg.RatingDBType = "test"
- eCfg.RatingDBHost = "test"
- eCfg.RatingDBPort = "test"
- eCfg.RatingDBName = "test"
- eCfg.RatingDBUser = "test"
- eCfg.RatingDBPass = "test"
- eCfg.AccountDBType = "test"
- eCfg.AccountDBHost = "test"
- eCfg.AccountDBPort = "test"
- eCfg.AccountDBName = "test"
- eCfg.AccountDBUser = "test"
- eCfg.AccountDBPass = "test"
- eCfg.StorDBType = "test"
- eCfg.StorDBHost = "test"
- eCfg.StorDBPort = "test"
- eCfg.StorDBName = "test"
- eCfg.StorDBUser = "test"
- eCfg.StorDBPass = "test"
- eCfg.StorDBMaxOpenConns = 99
- eCfg.StorDBMaxIdleConns = 99
- eCfg.DBDataEncoding = "test"
- eCfg.RPCJSONListen = "test"
- eCfg.RPCGOBListen = "test"
- eCfg.HTTPListen = "test"
- eCfg.DefaultReqType = "test"
- eCfg.DefaultCategory = "test"
- eCfg.DefaultTenant = "test"
- eCfg.DefaultSubject = "test"
- eCfg.RoundingDecimals = 99
- eCfg.HttpSkipTlsVerify = true
- eCfg.TpExportPath = "test"
- eCfg.RaterEnabled = true
- eCfg.RaterBalancer = "test"
- eCfg.BalancerEnabled = true
- eCfg.SchedulerEnabled = true
- eCfg.CDRSEnabled = true
- eCfg.CDRSExtraFields = []*utils.RSRField{&utils.RSRField{Id: "test"}}
- eCfg.CDRSMediator = "test"
- eCfg.CDRSStats = "test"
- eCfg.CDRSStoreDisable = true
- eCfg.CDRStatsEnabled = true
- eCfg.CDRStatConfig = &CdrStatsConfig{Id: utils.META_DEFAULT, QueueLength: 99, TimeWindow: time.Duration(99) * time.Second,
- Metrics: []string{"test"}, TORs: []string{"test"}, CdrHosts: []string{"test"}, CdrSources: []string{"test"}, ReqTypes: []string{"test"}, Directions: []string{"test"},
- Tenants: []string{"test"}, Categories: []string{"test"}, Accounts: []string{"test"}, Subjects: []string{"test"}, DestinationPrefixes: []string{"test"},
- UsageInterval: []time.Duration{time.Duration(99) * time.Second},
- MediationRunIds: []string{"test"}, RatedAccounts: []string{"test"}, RatedSubjects: []string{"test"}, CostInterval: []float64{99.0}}
- eCfg.CDRSStats = "test"
- eCfg.CdreDefaultInstance = &CdreConfig{
- CdrFormat: "test",
- FieldSeparator: utils.CSV_SEP,
- DataUsageMultiplyFactor: 99.0,
- CostMultiplyFactor: 99.0,
- CostRoundingDecimals: 99,
- CostShiftDigits: 99,
- MaskDestId: "test",
- MaskLength: 99,
- ExportDir: "test"}
- eCfg.CdreDefaultInstance.ContentFields, _ = NewCfgCdrFieldsFromIds(false, "test")
- cdrcCfg := NewDefaultCdrcConfig()
- cdrcCfg.Enabled = true
- cdrcCfg.CdrsAddress = "test"
- cdrcCfg.RunDelay = time.Duration(99) * time.Second
- cdrcCfg.CdrFormat = "test"
- cdrcCfg.FieldSeparator = ";"
- cdrcCfg.DataUsageMultiplyFactor = 99.0
- cdrcCfg.CdrInDir = "test"
- cdrcCfg.CdrOutDir = "test"
- cdrcCfg.CdrSourceId = "test"
- cdrcCfg.CdrFields = []*CfgCdrField{
- &CfgCdrField{Tag: utils.TOR, Type: utils.CDRFIELD, CdrFieldId: utils.TOR, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: utils.ACCID, Type: utils.CDRFIELD, CdrFieldId: utils.ACCID, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: utils.REQTYPE, Type: utils.CDRFIELD, CdrFieldId: utils.REQTYPE, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: utils.DIRECTION, Type: utils.CDRFIELD, CdrFieldId: utils.DIRECTION, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: utils.TENANT, Type: utils.CDRFIELD, CdrFieldId: utils.TENANT, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: utils.CATEGORY, Type: utils.CDRFIELD, CdrFieldId: utils.CATEGORY, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: utils.ACCOUNT, Type: utils.CDRFIELD, CdrFieldId: utils.ACCOUNT, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: utils.SUBJECT, Type: utils.CDRFIELD, CdrFieldId: utils.SUBJECT, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: utils.DESTINATION, Type: utils.CDRFIELD, CdrFieldId: utils.DESTINATION, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: utils.SETUP_TIME, Type: utils.CDRFIELD, CdrFieldId: utils.SETUP_TIME, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true, Layout: "2006-01-02T15:04:05Z07:00"},
- &CfgCdrField{Tag: utils.ANSWER_TIME, Type: utils.CDRFIELD, CdrFieldId: utils.ANSWER_TIME, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true, Layout: "2006-01-02T15:04:05Z07:00"},
- &CfgCdrField{Tag: utils.USAGE, Type: utils.CDRFIELD, CdrFieldId: utils.USAGE, Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}, Mandatory: true},
- &CfgCdrField{Tag: "test", Type: utils.CDRFIELD, CdrFieldId: "test", Value: []*utils.RSRField{&utils.RSRField{Id: "test"}}},
- }
- eCfg.CdrcInstances = []*CdrcConfig{cdrcCfg}
- eCfg.MediatorEnabled = true
- eCfg.MediatorRater = "test"
- eCfg.MediatorReconnects = 99
- eCfg.MediatorStats = "test"
- eCfg.MediatorStoreDisable = true
- eCfg.SMEnabled = true
- eCfg.SMSwitchType = "test"
- eCfg.SMRater = "test"
- eCfg.SMCdrS = "test"
- eCfg.SMReconnects = 99
- eCfg.SMDebitInterval = 99
- eCfg.SMMinCallDuration = time.Duration(98) * time.Second
- eCfg.SMMaxCallDuration = time.Duration(99) * time.Second
- eCfg.FreeswitchServer = "test"
- eCfg.FreeswitchPass = "test"
- eCfg.FreeswitchReconnects = 99
- eCfg.FSMinDurLowBalance = time.Duration(99) * time.Second
- eCfg.FSLowBalanceAnnFile = "test"
- eCfg.FSEmptyBalanceContext = "test"
- eCfg.FSEmptyBalanceAnnFile = "test"
- eCfg.FSCdrExtraFields = []*utils.RSRField{&utils.RSRField{Id: "test"}}
- eCfg.OsipsListenUdp = "test"
- eCfg.OsipsMiAddr = "test"
- eCfg.OsipsEvSubscInterval = time.Duration(99) * time.Second
- eCfg.OsipsReconnects = 99
- eCfg.KamailioEvApiAddr = "test"
- eCfg.KamailioReconnects = 99
- eCfg.DerivedChargers = utils.DerivedChargers{&utils.DerivedCharger{RunId: "test", RunFilters: "", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
- CategoryField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", UsageField: "test"}}
- eCfg.CombinedDerivedChargers = true
- eCfg.HistoryAgentEnabled = true
- eCfg.HistoryServer = "test"
- eCfg.HistoryServerEnabled = true
- eCfg.HistoryDir = "test"
- eCfg.HistorySaveInterval = time.Duration(99) * time.Second
- eCfg.MailerServer = "test"
- eCfg.MailerAuthUser = "test"
- eCfg.MailerAuthPass = "test"
- eCfg.MailerFromAddr = "test"
- eCfg.DataFolderPath = "/usr/share/cgrates/"
- if !reflect.DeepEqual(cfg, eCfg) {
- t.Log(eCfg)
- t.Log(cfg)
- t.Error("Loading of configuration from file failed!")
- }
-
-}
-
-func TestCdrsExtraFields(t *testing.T) {
- eFieldsCfg := []byte(`[cdrs]
-extra_fields = extr1,extr2
-`)
- if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil {
- t.Error("Could not parse the config", err.Error())
- } else if !reflect.DeepEqual(cfg.CDRSExtraFields, []*utils.RSRField{&utils.RSRField{Id: "extr1"}, &utils.RSRField{Id: "extr2"}}) {
- t.Errorf("Unexpected value for CdrsExtraFields: %v", cfg.CDRSExtraFields)
- }
- eFieldsCfg = []byte(`[cdrs]
-extra_fields = ~effective_caller_id_number:s/(\d+)/+$1/
-`)
- if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil {
- t.Error("Could not parse the config", err.Error())
- } else if !reflect.DeepEqual(cfg.CDRSExtraFields, []*utils.RSRField{&utils.RSRField{Id: "effective_caller_id_number",
- RSRules: []*utils.ReSearchReplace{&utils.ReSearchReplace{SearchRegexp: regexp.MustCompile(`(\d+)`), ReplaceTemplate: "+$1"}}}}) {
- t.Errorf("Unexpected value for config CdrsExtraFields: %v", cfg.CDRSExtraFields)
- }
- eFieldsCfg = []byte(`[cdrs]
-extra_fields = extr1,~extr2:s/x.+/
-`)
- if _, err := NewCGRConfigFromBytes(eFieldsCfg); err == nil {
- t.Error("Failed to detect failed RSRParsing")
- }
-
-}
-
-func TestCdreExtraFields(t *testing.T) {
- eFieldsCfg := []byte(`[cdre]
-cdr_format = csv
-export_template = cgrid,mediation_runid,accid
-`)
- expectedFlds := []*CfgCdrField{
- &CfgCdrField{Tag: "cgrid", Type: utils.CDRFIELD, CdrFieldId: "cgrid", Value: []*utils.RSRField{&utils.RSRField{Id: "cgrid"}}, Mandatory: true},
- &CfgCdrField{Tag: "mediation_runid", Type: utils.CDRFIELD, CdrFieldId: "mediation_runid", Value: []*utils.RSRField{&utils.RSRField{Id: "mediation_runid"}}, Mandatory: true},
- &CfgCdrField{Tag: "accid", Type: utils.CDRFIELD, CdrFieldId: "accid", Value: []*utils.RSRField{&utils.RSRField{Id: "accid"}}, Mandatory: true},
- }
- expCdreCfg := &CdreConfig{CdrFormat: utils.CSV, FieldSeparator: utils.CSV_SEP, CostRoundingDecimals: -1, ExportDir: "/var/log/cgrates/cdre", ContentFields: expectedFlds}
- if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil {
- t.Error("Could not parse the config", err.Error())
- } else if !reflect.DeepEqual(cfg.CdreDefaultInstance, expCdreCfg) {
- t.Errorf("Expecting: %v, received: %v", expCdreCfg, cfg.CdreDefaultInstance)
- }
- eFieldsCfg = []byte(`[cdre]
-cdr_format = csv
-export_template = cgrid,~effective_caller_id_number:s/(\d+)/+$1/
-`)
- rsrField, _ := utils.NewRSRField(`~effective_caller_id_number:s/(\d+)/+$1/`)
- expectedFlds = []*CfgCdrField{
- &CfgCdrField{Tag: "cgrid", Type: utils.CDRFIELD, CdrFieldId: "cgrid", Value: []*utils.RSRField{&utils.RSRField{Id: "cgrid"}}, Mandatory: true},
- &CfgCdrField{Tag: "effective_caller_id_number", Type: utils.CDRFIELD, CdrFieldId: "effective_caller_id_number", Value: []*utils.RSRField{rsrField}, Mandatory: false}}
- expCdreCfg.ContentFields = expectedFlds
- if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil {
- t.Error("Could not parse the config", err.Error())
- } else if !reflect.DeepEqual(cfg.CdreDefaultInstance, expCdreCfg) {
- t.Errorf("Expecting: %v, received: %v", expCdreCfg, cfg.CdreDefaultInstance)
- }
- eFieldsCfg = []byte(`[cdre]
-cdr_format = csv
-export_template = cgrid,~accid:s/(\d)/$1,runid
-`)
- if _, err := NewCGRConfigFromBytes(eFieldsCfg); err == nil {
- t.Error("Failed to detect failed RSRParsing")
- }
-}
diff --git a/config/helpers.go b/config/helpers.go
deleted file mode 100644
index baeb6e422..000000000
--- a/config/helpers.go
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
-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 (
- "code.google.com/p/goconf/conf"
- "errors"
- "fmt"
- "strings"
-
- "github.com/cgrates/cgrates/utils"
-)
-
-// Adds support for slice values in config
-func ConfigSlice(cfgVal string) ([]string, error) {
- cfgValStrs := strings.Split(cfgVal, utils.FIELDS_SEP) // If need arrises, we can make the separator configurable
- for idx, elm := range cfgValStrs {
- cfgValStrs[idx] = strings.TrimSpace(elm) // By default spaces are not removed so we do it here to avoid unpredicted results in config
- }
- return cfgValStrs, nil
-}
-
-// Parse the configuration file and returns utils.DerivedChargers instance if no errors
-func ParseCfgDerivedCharging(c *conf.ConfigFile) (dcs utils.DerivedChargers, err error) {
- var runIds, runFilters, reqTypeFlds, directionFlds, tenantFlds, torFlds, acntFlds, subjFlds, dstFlds, sTimeFlds, aTimeFlds, durFlds []string
- cfgVal, _ := c.GetString("derived_charging", "run_ids")
- if runIds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "run_filters")
- if runFilters, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "reqtype_fields")
- if reqTypeFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "direction_fields")
- if directionFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "tenant_fields")
- if tenantFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "category_fields")
- if torFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "account_fields")
- if acntFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "subject_fields")
- if subjFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "destination_fields")
- if dstFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "setup_time_fields")
- if sTimeFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "answer_time_fields")
- if aTimeFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- cfgVal, _ = c.GetString("derived_charging", "usage_fields")
- if durFlds, err = ConfigSlice(cfgVal); err != nil {
- return nil, err
- }
- // We need all to be the same length
- if len(runFilters) != len(runIds) ||
- len(reqTypeFlds) != len(runIds) ||
- len(directionFlds) != len(runIds) ||
- len(tenantFlds) != len(runIds) ||
- len(torFlds) != len(runIds) ||
- len(acntFlds) != len(runIds) ||
- len(subjFlds) != len(runIds) ||
- len(dstFlds) != len(runIds) ||
- len(sTimeFlds) != len(runIds) ||
- len(aTimeFlds) != len(runIds) ||
- len(durFlds) != len(runIds) {
- return nil, errors.New(" Inconsistent fields length in derivated_charging section")
- }
- // Create the individual chargers and append them to the final instance
- dcs = make(utils.DerivedChargers, 0)
- if len(runIds) == 1 && len(runIds[0]) == 0 { // Avoid iterating on empty runid
- return dcs, nil
- }
- for runIdx, runId := range runIds {
- dc, err := utils.NewDerivedCharger(runId, runFilters[runIdx], reqTypeFlds[runIdx], directionFlds[runIdx], tenantFlds[runIdx], torFlds[runIdx],
- acntFlds[runIdx], subjFlds[runIdx], dstFlds[runIdx], sTimeFlds[runIdx], aTimeFlds[runIdx], durFlds[runIdx])
- if err != nil {
- return nil, err
- }
- if dcs, err = dcs.Append(dc); err != nil {
- return nil, err
- }
- }
- return dcs, nil
-}
-
-func ParseCdrcCdrFields(torFld, accIdFld, reqtypeFld, directionFld, tenantFld, categoryFld, acntFld, subjectFld, destFld,
- setupTimeFld, answerTimeFld, durFld, extraFlds string) (map[string][]*utils.RSRField, error) {
- cdrcCdrFlds := make(map[string][]*utils.RSRField)
- if len(extraFlds) != 0 {
- if sepExtraFlds, err := ConfigSlice(extraFlds); err != nil {
- return nil, err
- } else {
- for _, fldStr := range sepExtraFlds {
- // extra fields defined as: :
- if spltLbl := strings.Split(fldStr, utils.CONCATENATED_KEY_SEP); len(spltLbl) != 2 {
- return nil, fmt.Errorf("Wrong format for cdrc.extra_fields: %s", fldStr)
- } else {
- if rsrFlds, err := utils.ParseRSRFields(spltLbl[1], utils.INFIELD_SEP); err != nil {
- return nil, err
- } else {
- cdrcCdrFlds[spltLbl[0]] = rsrFlds
- }
- }
- }
- }
- }
- for fldTag, fldVal := range map[string]string{utils.TOR: torFld, utils.ACCID: accIdFld, utils.REQTYPE: reqtypeFld, utils.DIRECTION: directionFld, utils.TENANT: tenantFld,
- utils.CATEGORY: categoryFld, utils.ACCOUNT: acntFld, utils.SUBJECT: subjectFld, utils.DESTINATION: destFld, utils.SETUP_TIME: setupTimeFld,
- utils.ANSWER_TIME: answerTimeFld, utils.USAGE: durFld} {
- if len(fldVal) != 0 {
- if rsrFlds, err := utils.ParseRSRFields(fldVal, utils.INFIELD_SEP); err != nil {
- return nil, err
- } else {
- cdrcCdrFlds[fldTag] = rsrFlds
- }
- }
- }
- return cdrcCdrFlds, nil
-}
diff --git a/config/helpers_test.go b/config/helpers_test.go
deleted file mode 100644
index 8238bafa0..000000000
--- a/config/helpers_test.go
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
-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/json"
- "reflect"
- "testing"
-
- "github.com/cgrates/cgrates/utils"
-)
-
-func TestConfigSlice(t *testing.T) {
- eCS := []string{"", ""}
- if cs, err := ConfigSlice(" , "); err != nil {
- t.Error("Unexpected error: ", err)
- } else if !reflect.DeepEqual(eCS, cs) {
- t.Errorf("Expecting: %v, received: %v", eCS, cs)
- }
-}
-
-func TestParseCfgDerivedCharging(t *testing.T) {
- eFieldsCfg := []byte(`[derived_charging]
-run_ids = run1, run2
-run_filters =,
-reqtype_fields = test1, test2
-direction_fields = test1, test2
-tenant_fields = test1, test2
-category_fields = test1, test2
-account_fields = test1, test2
-subject_fields = test1, test2
-destination_fields = test1, test2
-setup_time_fields = test1, test2
-answer_time_fields = test1, test2
-usage_fields = test1, test2
-`)
- edcs := utils.DerivedChargers{
- &utils.DerivedCharger{RunId: "run1", ReqTypeField: "test1", DirectionField: "test1", TenantField: "test1", CategoryField: "test1",
- AccountField: "test1", SubjectField: "test1", DestinationField: "test1", SetupTimeField: "test1", AnswerTimeField: "test1", UsageField: "test1"},
- &utils.DerivedCharger{RunId: "run2", ReqTypeField: "test2", DirectionField: "test2", TenantField: "test2", CategoryField: "test2",
- AccountField: "test2", SubjectField: "test2", DestinationField: "test2", SetupTimeField: "test2", AnswerTimeField: "test2", UsageField: "test2"}}
- if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil {
- t.Error("Could not parse the config", err.Error())
- } else if !reflect.DeepEqual(cfg.DerivedChargers, edcs) {
- t.Errorf("Expecting: %v, received: %v", edcs, cfg.DerivedChargers)
- }
-}
-
-func TestParseCfgDerivedChargingDn1(t *testing.T) {
- eFieldsCfg := []byte(`[derived_charging]
-run_ids = run1, run2
-run_filters =~account:s/^\w+[mpls]\d{6}$//,~account:s/^0\d{9}$//;^account/value/
-reqtype_fields = test1, test2
-direction_fields = test1, test2
-tenant_fields = test1, test2
-category_fields = test1, test2
-account_fields = test1, test2
-subject_fields = test1, test2
-destination_fields = test1, test2
-setup_time_fields = test1, test2
-answer_time_fields = test1, test2
-usage_fields = test1, test2
-`)
- eDcs := make(utils.DerivedChargers, 2)
- if dc, err := utils.NewDerivedCharger("run1", `~account:s/^\w+[mpls]\d{6}$//`, "test1", "test1", "test1",
- "test1", "test1", "test1", "test1", "test1", "test1", "test1"); err != nil {
- t.Error("Unexpected error: ", err)
- } else {
- eDcs[0] = dc
- }
- if dc, err := utils.NewDerivedCharger("run2", `~account:s/^0\d{9}$//;^account/value/`, "test2", "test2", "test2",
- "test2", "test2", "test2", "test2", "test2", "test2", "test2"); err != nil {
- t.Error("Unexpected error: ", err)
- } else {
- eDcs[1] = dc
- }
-
- if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil {
- t.Error("Could not parse the config", err.Error())
- } else if !reflect.DeepEqual(cfg.DerivedChargers, eDcs) {
- dcsJson, _ := json.Marshal(cfg.DerivedChargers)
- t.Errorf("Received: %s", string(dcsJson))
- }
-}
-
-func TestParseCdrcCdrFields(t *testing.T) {
- eCdrcCdrFlds := map[string][]*utils.RSRField{
- utils.TOR: []*utils.RSRField{&utils.RSRField{Id: "tor1"}},
- utils.ACCID: []*utils.RSRField{&utils.RSRField{Id: "accid1"}},
- utils.REQTYPE: []*utils.RSRField{&utils.RSRField{Id: "reqtype1"}},
- utils.DIRECTION: []*utils.RSRField{&utils.RSRField{Id: "direction1"}},
- utils.TENANT: []*utils.RSRField{&utils.RSRField{Id: "tenant1"}},
- utils.CATEGORY: []*utils.RSRField{&utils.RSRField{Id: "category1"}},
- utils.ACCOUNT: []*utils.RSRField{&utils.RSRField{Id: "account1"}},
- utils.SUBJECT: []*utils.RSRField{&utils.RSRField{Id: "subject1"}},
- utils.DESTINATION: []*utils.RSRField{&utils.RSRField{Id: "destination1"}},
- utils.SETUP_TIME: []*utils.RSRField{&utils.RSRField{Id: "setuptime1"}},
- utils.ANSWER_TIME: []*utils.RSRField{&utils.RSRField{Id: "answertime1"}},
- utils.USAGE: []*utils.RSRField{&utils.RSRField{Id: "duration1"}},
- "extra1": []*utils.RSRField{&utils.RSRField{Id: "extraval1"}},
- "extra2": []*utils.RSRField{&utils.RSRField{Id: "extraval1"}},
- }
- if cdrFlds, err := ParseCdrcCdrFields("tor1", "accid1", "reqtype1", "direction1", "tenant1", "category1", "account1", "subject1", "destination1",
- "setuptime1", "answertime1", "duration1", "extra1:extraval1,extra2:extraval1"); err != nil {
- t.Error("Could not parse the config", err.Error())
- } else if !reflect.DeepEqual(eCdrcCdrFlds, cdrFlds) {
- t.Errorf("Expecting: %v, received: %v, tor: %v", eCdrcCdrFlds, cdrFlds, cdrFlds[utils.TOR])
- }
-}
diff --git a/config/libconfig_json.go b/config/libconfig_json.go
index aecb13696..24e37067a 100644
--- a/config/libconfig_json.go
+++ b/config/libconfig_json.go
@@ -104,7 +104,7 @@ type CdrStatsJsonCfg struct {
Mediation_run_ids *[]string
Rated_accounts *[]string
Rated_subjects *[]string
- Cost_intervals *[]string
+ Cost_interval *[]float64
}
// One cdr field config, used in cdre and cdrc
@@ -124,6 +124,7 @@ type CdrFieldJsonCfg struct {
// Cdre config section
type CdreJsonCfg struct {
Cdr_format *string
+ Field_separator *string
Data_usage_multiply_factor *float64
Cost_multiply_factor *float64
Cost_rounding_decimals *int
diff --git a/config/test_data.txt b/config/test_data.txt
deleted file mode 100644
index 9c6a73d75..000000000
--- a/config/test_data.txt
+++ /dev/null
@@ -1,177 +0,0 @@
-# TEST DATA - NOT FOR PRODUCTION USAGE
-#
-
-[global]
-ratingdb_type = test # Rating subsystem database: .
-ratingdb_host = test # Rating subsystem database host address.
-ratingdb_port = test # Rating subsystem port to reach the database.
-ratingdb_name = test # Rating subsystem database name to connect to.
-ratingdb_user = test # Rating subsystem username to use when connecting to database.
-ratingdb_passwd = test # Rating subsystem password to use when connecting to database.
-accountdb_type = test # Accounting subsystem database: .
-accountdb_host = test # Accounting subsystem database host address.
-accountdb_port = test # Accounting subsystem port to reach the database.
-accountdb_name = test # Accounting subsystem database name to connect to.
-accountdb_user = test # Accounting subsystem username to use when connecting to database.
-accountdb_passwd = test # Accounting subsystem password to use when connecting to database.
-stordb_type = test # Log/scategoryed database type to use:
-stordb_host = test # The host to connect to. Values that start with / are for UNIX domain sockets.
-stordb_port = test # The port to reach the logdb.
-stordb_name = test # The name of the log database to connect to.
-stordb_user = test # Username to use when connecting to logdb.
-stordb_passwd = test # Password to use when connecting to logdb.
-stordb_max_open_conns = 99 # Maximum database connections opened
-stordb_max_idle_conns = 99 # Maximum database connections idle
-dbdata_encoding = test # The encoding used to scategorye object data in strings:
-rpc_json_listen = test # RPC JSON listening address
-rpc_gob_listen = test # RPC GOB listening address
-http_listen = test # HTTP listening address
-default_reqtype = test # Default request type to consider when missing from requests: <""|prepaid|postpaid|pseudoprepaid|rated>.
-default_category = test # Default Type of Record to consider when missing from requests.
-default_tenant = test # Default Tenant to consider when missing from requests.
-default_subject = test # Default rating Subject to consider when missing from requests.
-rounding_decimals = 99 # Number of decimals to round floats/costs at
-http_skip_tls_veify = true # If enabled Http Client will accept any TLS certificate
-tpexport_dir = test # Path towards export folder for offline Tariff Plans
-
-[balancer]
-enabled = true # Start Balancer service: .
-
-[rater]
-enabled = true # Enable Rater service: .
-balancer = test # Register to Balancer as worker: .
-
-[scheduler]
-enabled = true # Starts Scheduler service: .
-
-[cdrs]
-enabled = true # Start the CDR Server service: .
-extra_fields = test # Extra fields to scategorye in CDRs
-mediator = test # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
-cdrstats = test # Address where to reach the CDRStats server. Empty for disabling stats. <""|internal>
-store_disable = true # When true, CDRs will not longer be saved in stordb, useful for cdrstats only scenario
-
-[cdre]
-cdr_format = test # Exported CDRs format
-data_usage_multiply_factor = 99.0 # Multiply data usage before export (eg: convert from KBytes to Bytes)
-cost_multiply_factor = 99.0 # Multiply cost before export (0.0 to disable), eg: add VAT
-cost_rounding_decimals = 99 # Rounding decimals for Cost values. -1 to disable rounding
-cost_shift_digits = 99 # Shift digits in the cost on export (eg: convert from EUR to cents)
-mask_destination_id = test # Destination id containing called addresses to be masked on export
-mask_length = 99 # Length of the destination suffix to be masked
-export_dir = test # Path where the exported CDRs will be placed
-export_template = test # List of fields in the exported CDRs
-
-[cdrc]
-enabled = true # Enable CDR client functionality
-cdrs = test # Address where to reach CDR server
-run_delay = 99 # Period to sleep between two runs, 0 to use automation via inotify
-cdr_format = test # CDR file format .
-field_separator =; # Csv separator, one character only and should be next to equal sign
-data_usage_multiply_factor = 99
-cdr_in_dir = test # Absolute path towards the direccategoryy where the CDRs are kept (file scategoryed CDRs).
-cdr_out_dir = test # Absolute path towards the direccategoryy where processed CDRs will be moved after processing.
-cdr_source_id = test # Tag identifying the source of the CDRs within CGRS database.
-tor_field = test # TypeOfRecord field identifier. Use index number in case of .csv cdrs.
-accid_field = test # Accounting id field identifier. Use index number in case of .csv cdrs.
-reqtype_field = test # Request type field identifier. Use index number in case of .csv cdrs.
-direction_field = test # Direction field identifier. Use index numbers in case of .csv cdrs.
-tenant_field = test # Tenant field identifier. Use index numbers in case of .csv cdrs.
-category_field = test # Type of Record field identifier. Use index numbers in case of .csv cdrs.
-account_field = test # Account field identifier. Use index numbers in case of .csv cdrs.
-subject_field = test # Subject field identifier. Use index numbers in case of .csv CDRs.
-destination_field = test # Destination field identifier. Use index numbers in case of .csv cdrs.
-setup_time_field = test # Answer time field identifier. Use index numbers in case of .csv cdrs.
-answer_time_field = test # Answer time field identifier. Use index numbers in case of .csv cdrs.
-usage_field = test # Duration field identifier. Use index numbers in case of .csv cdrs.
-extra_fields = test:test # Field identifiers of the fields to add in extra fields section, special format in case of .csv "index1|field1,index2|field2"
-
-[mediator]
-enabled = true # Starts Mediacategory service: .
-rater = test # Address where to reach the Rater:
-reconnects = 99 # Number of reconnects to rater before giving up.
-cdrstats = test # Address where to reach the cdrstats service:
-store_disable = true # When true, CDRs will not longer be saved in stordb, useful for cdrstats only scenario
-
-[cdrstats]
-enabled = true # Start the CDR stats service: .
-queue_length = 99 # Number of items in the stats buffer
-time_window = 99 # Will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow
-metrics = test # Stat metric ids to build
-setup_interval = # Filter on CDR SetupTime
-tors = test # Filter on CDR TOR fields
-cdr_hosts= test # Filter on CDR CdrHost fields
-cdr_sources = test # Filter on CDR CdrSource fields
-req_types = test # Filter on CDR ReqType fields
-directions = test # Filter on CDR Direction fields
-tenants = test # Filter on CDR Tenant fields
-categories = test # Filter on CDR Category fields
-accounts = test # Filter on CDR Account fields
-subjects = test # Filter on CDR Subject fields
-destination_prefixes = test # Filter on CDR Destination prefixes
-usage_interval = 99 # Filter on CDR Usage
-mediation_run_ids = test # Filter on CDR MediationRunId fields
-rated_accounts = test # Filter on CDR RatedAccount fields
-rated_subjects = test # Filter on CDR RatedSubject fields
-cost_intervals = 99 # Filter on CDR Cost
-
-[session_manager]
-enabled = true # Starts SessionManager service: .
-switch_type = test # Defines the type of switch behind: .
-rater = test # Address where to reach the Rater.
-cdrs = test # Address where to reach CDR Server, empty to disable CDR capturing <""|internal|127.0.0.1:2013>
-reconnects = 99 # Number of reconnects to rater before giving up.
-debit_interval = 99 # Interval to perform debits on.
-min_call_duration = 98 # Only authorize calls with allowed duration bigger than this
-max_call_duration = 99 # Maximum call duration a prepaid call can last
-
-[freeswitch]
-server = test # Adress where to connect to FreeSWITCH socket.
-passwd = test # FreeSWITCH socket password.
-reconnects = 99 # Number of attempts on connect failure.
-min_dur_low_balance = 99 # Threshold which will trigger low balance warnings
-low_balance_ann_file = test # File to be played when low balance is reached
-empty_balance_context = test # If defined, call will be transfered to this context on empty balance
-empty_balance_ann_file = test # File to be played before disconnecting prepaid calls (applies only if no context defined)
-cdr_extra_fields = test # Extra fields to store in CDRs in case of processing them
-
-[kamailio]
-evapi_addr = test
-reconnects = 99 # Number of attempts on connect failure.
-
-[opensips]
-listen_udp = test # Address where to listen for event datagrams coming from OpenSIPS
-mi_addr = test # Adress where to reach OpenSIPS mi_datagram module
-events_subscribe_interval = 99 # Automatic events subscription to OpenSIPS, 0 to disable it
-cdrs = test # Address where to reach CDR Server, empty to disable CDR processing <""|internal|127.0.0.1:2013>
-reconnects = 99 # Number of attempts on connect failure.
-
-[derived_charging]
-run_ids = test # Identifiers of additional sessions control.
-run_filters = # No filters applied
-reqtype_fields = test # Name of request type fields to be used during additional sessions control <""|*default|field_name>.
-direction_fields = test # Name of direction fields to be used during additional sessions control <""|*default|field_name>.
-tenant_fields = test # Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
-category_fields = test # Name of category fields to be used during additional sessions control <""|*default|field_name>.
-account_fields = test # Name of account fields to be used during additional sessions control <""|*default|field_name>.
-subject_fields = test # Name of fields to be used during additional sessions control <""|*default|field_name>.
-destination_fields = test # Name of destination fields to be used during additional sessions control <""|*default|field_name>.
-setup_time_fields = test # Name of setup_time fields to be used during additional sessions control <""|*default|field_name>.
-answer_time_fields = test # Name of answer_time fields to be used during additional sessions control <""|*default|field_name>.
-usage_fields = test # Name of duration fields to be used during additional sessions control <""|*default|field_name>.
-combined_chargers = true # Combine accounts specific derived_chargers with server configured ones .
-
-[history_server]
-enabled = true # Starts Hiscategoryy service: .
-history_dir = test # Location on disk where to scategorye hiscategoryy files.
-save_interval = 99 # Timeout duration between saves
-
-[history_agent]
-enabled = true # Starts Hiscategoryy as a client: .
-server = test # Address where to reach the master hiscategoryy server:
-
-[mailer]
-server = test # The server to use when sending emails out
-auth_user = test # Authenticate to email server using this user
-auth_passwd = test # Authenticate to email server with this password
-from_address = test # From address used when sending emails out
diff --git a/config/xmlcdrc_test.go b/config/xmlcdrc_test.go
deleted file mode 100644
index d34df847c..000000000
--- a/config/xmlcdrc_test.go
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
-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 TestSetDefaults(t *testing.T) {
- cfgXmlStr := `
-
-
- true
-
-`
- var xmlCdrc *CgrXmlCdrcCfg
- reader := strings.NewReader(cfgXmlStr)
- if cfgDocCdrcDf, err := ParseCgrXmlConfig(reader); err != nil {
- t.Error(err.Error())
- } else if cfgDocCdrcDf == nil {
- t.Fatal("Could not parse xml configuration document")
- } else if len(cfgDocCdrcDf.cdrcs) != 1 {
- t.Error("Did not load cdrc")
- } else {
- xmlCdrc = cfgDocCdrcDf.cdrcs["CDRC-CSVDF"]
- }
- dfCfg, _ := NewDefaultCGRConfig()
- xmlCdrc.setDefaults()
- if xmlCdrc.CdrsAddress != dfCfg.CdrcCdrs ||
- xmlCdrc.CdrFormat != dfCfg.CdrcCdrType ||
- xmlCdrc.CsvSeparator != dfCfg.CdrcCsvSep ||
- xmlCdrc.CdrInDir != dfCfg.CdrcCdrInDir ||
- xmlCdrc.CdrOutDir != dfCfg.CdrcCdrOutDir ||
- xmlCdrc.CdrSourceId != dfCfg.CdrcSourceId ||
- len(xmlCdrc.CdrFields) != len(dfCfg.CdrcCdrFields) {
- t.Error("Failed loading default configuration")
- }
-}
-*/
-
-func TestParseXmlCdrcConfig(t *testing.T) {
- cfgXmlStr := `
-
-
- true
- internal
- csv
- ,
- 1024
- 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 TestGetCdrcCfgs(t *testing.T) {
- cdrcfgs := cfgDocCdrc.GetCdrcCfgs("CDRC-CSV1")
- if cdrcfgs == nil {
- t.Error("No config instance returned")
- }
- enabled := true
- cdrsAddr := "internal"
- cdrFormat := "csv"
- fldSep := ","
- dataUsageMultiplyFactor := 1024.0
- runDelay := int64(0)
- cdrInDir := "/var/log/cgrates/cdrc/in"
- cdrOutDir := "/var/log/cgrates/cdrc/out"
- cdrSrcId := "freeswitch_csv"
- expectCdrc := &CgrXmlCdrcCfg{Enabled: &enabled, CdrsAddress: &cdrsAddr, CdrFormat: &cdrFormat, FieldSeparator: &fldSep, DataUsageMultiplyFactor: &dataUsageMultiplyFactor,
- RunDelay: &runDelay, CdrInDir: &cdrInDir, CdrOutDir: &cdrOutDir, CdrSourceId: &cdrSrcId}
- accIdTag, reqTypeTag, dirTag, tntTag, categTag, acntTag, subjTag, dstTag, sTimeTag, aTimeTag, usageTag, extr1, extr2 := utils.ACCID,
- utils.REQTYPE, utils.DIRECTION, utils.TENANT, utils.CATEGORY, utils.ACCOUNT, utils.SUBJECT, utils.DESTINATION, utils.SETUP_TIME, utils.ANSWER_TIME, utils.USAGE, "extr1", "extr2"
- accIdVal, reqVal, dirVal, tntVal, categVal, acntVal, subjVal, dstVal, sTimeVal, aTimeVal, usageVal, extr1Val, extr2Val := "0;13", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"
- cdrFlds := []*XmlCfgCdrField{
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &accIdTag, Value: &accIdVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &reqTypeTag, Value: &reqVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &dirTag, Value: &dirVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &tntTag, Value: &tntVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &categTag, Value: &categVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &acntTag, Value: &acntVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &subjTag, Value: &subjVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &dstTag, Value: &dstVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &sTimeTag, Value: &sTimeVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &aTimeTag, Value: &aTimeVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &usageTag, Value: &usageVal},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &extr1, Value: &extr1Val},
- &XmlCfgCdrField{XMLName: xml.Name{Local: "field"}, Tag: &extr2, Value: &extr2Val}}
- expectCdrc.CdrFields = cdrFlds
- if !reflect.DeepEqual(expectCdrc, cdrcfgs["CDRC-CSV1"]) {
- t.Errorf("Expecting: %v, received: %v", expectCdrc, cdrcfgs["CDRC-CSV1"])
- }
-}
diff --git a/config/xmlcdre_test.go b/config/xmlcdre_test.go
deleted file mode 100644
index 298467af5..000000000
--- a/config/xmlcdre_test.go
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
-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 (
- "github.com/cgrates/cgrates/utils"
- "reflect"
- "strings"
- "testing"
-)
-
-var cfgDoc *CgrXmlCfgDocument // Will be populated by first test
-
-func TestXmlCdreCfgParseXmlConfig(t *testing.T) {
- cfgXmlStr := `
-
-
- fwv
- 1.0
- 0.0
- -1
- 0
- MASKED_DESTINATIONS
- 0
- /var/log/cgrates/cdre
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`
- var err error
- reader := strings.NewReader(cfgXmlStr)
- if cfgDoc, err = ParseCgrXmlConfig(reader); err != nil {
- t.Error(err.Error())
- } else if cfgDoc == nil {
- t.Fatal("Could not parse xml configuration document")
- }
- if len(cfgDoc.cdres) != 2 {
- t.Error("Did not cache")
- }
-}
-
-func TestXmlCdreCfgGetCdreCfg(t *testing.T) {
- cdreFWCfg := cfgDoc.GetCdreCfgs("CDRE-FW1")
- if cdreFWCfg == nil {
- t.Error("Could not parse CdreFw instance")
- }
- if len(cdreFWCfg["CDRE-FW1"].Header.Fields) != 8 {
- t.Error("Unexpected number of header fields parsed", len(cdreFWCfg["CDRE-FW1"].Header.Fields))
- }
- if len(cdreFWCfg["CDRE-FW1"].Content.Fields) != 20 {
- t.Error("Unexpected number of content fields parsed", len(cdreFWCfg["CDRE-FW1"].Content.Fields))
- }
- if len(cdreFWCfg["CDRE-FW1"].Trailer.Fields) != 9 {
- t.Error("Unexpected number of trailer fields parsed", len(cdreFWCfg["CDRE-FW1"].Trailer.Fields))
- }
- cdreCsvCfg1 := cfgDoc.GetCdreCfgs("CHECK-CSV1")
- if cdreCsvCfg1 == nil {
- t.Error("Could not parse CdreFw instance")
- }
- if len(cdreCsvCfg1["CHECK-CSV1"].Content.Fields) != 6 {
- t.Error("Unexpected number of content fields parsed", len(cdreCsvCfg1["CHECK-CSV1"].Content.Fields))
- }
-}
-
-func TestNewCdreConfigFromXmlCdreCfg(t *testing.T) {
- cfgXmlStr := `
-
-
- fwv
- ;
- 1024.0
- 1.19
- -1
- -3
- MASKED_DESTINATIONS
- 1
- /var/log/cgrates/cdre
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`
- var err error
- reader := strings.NewReader(cfgXmlStr)
- if cfgDoc, err = ParseCgrXmlConfig(reader); err != nil {
- t.Error(err.Error())
- } else if cfgDoc == nil {
- t.Fatal("Could not parse xml configuration document")
- }
- xmlCdreCfgs := cfgDoc.GetCdreCfgs("CDRE-FW2")
- if xmlCdreCfgs == nil {
- t.Error("Could not parse XmlCdre instance")
- }
- eCdreCfg := &CdreConfig{
- CdrFormat: "fwv",
- FieldSeparator: ';',
- DataUsageMultiplyFactor: 1024.0,
- CostMultiplyFactor: 1.19,
- CostRoundingDecimals: -1,
- CostShiftDigits: -3,
- MaskDestId: "MASKED_DESTINATIONS",
- MaskLength: 1,
- ExportDir: "/var/log/cgrates/cdre",
- }
- fltrCombiMed, _ := utils.ParseRSRFields("~mediation_runid:s/DEFAULT/SECOND_RUN/", utils.INFIELD_SEP)
- torVal, _ := utils.ParseRSRFields("^10", utils.INFIELD_SEP)
- lastCdrVal, _ := utils.ParseRSRFields("^last_cdr_time", utils.INFIELD_SEP)
- eCdreCfg.HeaderFields = []*CfgCdrField{
- &CfgCdrField{
- Tag: "TypeOfRecord",
- Type: "constant",
- Value: torVal,
- Width: 2,
- },
- &CfgCdrField{
- Tag: "LastCdr",
- Type: "metatag",
- CdrFieldId: "last_cdr_time",
- Value: lastCdrVal,
- Layout: "020106150400",
- Strip: "xright",
- Padding: "left",
- Width: 12,
- },
- }
- networkIdVal, _ := utils.ParseRSRFields("^3", utils.INFIELD_SEP)
- fromHttpPost1Val, _ := utils.ParseRSRFields("^https://localhost:8000", utils.INFIELD_SEP)
- eCdreCfg.ContentFields = []*CfgCdrField{
- &CfgCdrField{
- Tag: "OperatorCode",
- Type: "cdrfield",
- CdrFieldId: "operator",
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "operator"}},
- Width: 2,
- Strip: "xright",
- Padding: "left",
- },
- &CfgCdrField{
- Tag: "ProductId",
- Type: "cdrfield",
- CdrFieldId: "productid",
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "productid"}},
- Width: 5,
- Strip: "xright",
- Padding: "left",
- },
- &CfgCdrField{
- Tag: "NetworkId",
- Type: "constant",
- Value: networkIdVal,
- Width: 1,
- },
- &CfgCdrField{
- Tag: "FromHttpPost1",
- Type: "http_post",
- Value: fromHttpPost1Val,
- Width: 10,
- Strip: "xright",
- Padding: "left",
- },
- &CfgCdrField{
- Tag: "CombiMed1",
- Type: "combimed",
- CdrFieldId: "cost",
- Value: []*utils.RSRField{
- &utils.RSRField{Id: "cost"}},
- Width: 10,
- Strip: "xright",
- Padding: "left",
- Filter: fltrCombiMed,
- Mandatory: true,
- },
- }
- distribCodeVal, _ := utils.ParseRSRFields("^VOI", utils.INFIELD_SEP)
- fileSeqNrVal, _ := utils.ParseRSRFields("^export_id", utils.INFIELD_SEP)
- eCdreCfg.TrailerFields = []*CfgCdrField{
- &CfgCdrField{
- Tag: "DistributorCode",
- Type: "constant",
- Value: distribCodeVal,
- Width: 3,
- },
- &CfgCdrField{
- Tag: "FileSeqNr",
- Type: "metatag",
- CdrFieldId: "export_id",
- Value: fileSeqNrVal,
- Width: 5,
- Strip: "xright",
- Padding: "zeroleft",
- },
- }
- if rcvCdreCfg, err := NewCdreConfigFromXmlCdreCfg(xmlCdreCfgs["CDRE-FW2"]); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(rcvCdreCfg, eCdreCfg) {
- t.Errorf("Expecting: %v, received: %v", eCdreCfg, rcvCdreCfg)
- }
-}
diff --git a/config/xmlconfig.go b/config/xmlconfig.go
deleted file mode 100644
index a6433068b..000000000
--- a/config/xmlconfig.go
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
-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"
- "fmt"
- "github.com/cgrates/cgrates/utils"
- "io"
-)
-
-// Decodes a reader enforcing specific format of the configuration file
-func ParseCgrXmlConfig(reader io.Reader) (*CgrXmlCfgDocument, error) {
- xmlConfig := new(CgrXmlCfgDocument)
- decoder := xml.NewDecoder(reader)
- if err := decoder.Decode(xmlConfig); err != nil {
- return nil, err
- }
- if err := xmlConfig.cacheAll(); err != nil {
- return nil, err
- }
- return xmlConfig, nil
-}
-
-// XML CDR field, used for both cdrc and cdre
-type XmlCfgCdrField struct {
- XMLName xml.Name `xml:"field"`
- Tag *string `xml:"tag,attr"`
- Type *string `xml:"type,attr"`
- CdrFieldId *string `xml:"cdr_field,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
- Filter *string `xml:"filter,attr"` // Eg. combimed filters
- Mandatory *bool `xml:"mandatory,attr"` // If field is mandatory, empty value will be considered as error and CDR will not be exported
-}
-
-// One CDRC Configuration instance
-type CgrXmlCdrcCfg struct {
- Enabled *bool `xml:"enabled"` // Enable/Disable the
- CdrsAddress *string `xml:"cdrs_address"` // The address where CDRs can be reached
- CdrFormat *string `xml:"cdr_format"` // The type of CDR to process
- FieldSeparator *string `xml:"field_separator"` // The separator to use when reading csvs
- DataUsageMultiplyFactor *float64 `xml:"data_usage_multiply_factor"` // Conversion factor for data usage
- 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 []*XmlCfgCdrField `xml:"fields>field"`
-}
-
-// The CdrExporter configuration instance
-type CgrXmlCdreCfg struct {
- CdrFormat *string `xml:"cdr_format"`
- FieldSeparator *string `xml:"field_separator"`
- DataUsageMultiplyFactor *float64 `xml:"data_usage_multiply_factor"`
- CostMultiplyFactor *float64 `xml:"cost_multiply_factor"`
- CostRoundingDecimals *int `xml:"cost_rounding_decimals"`
- CostShiftDigits *int `xml:"cost_shift_digits"`
- MaskDestId *string `xml:"mask_destination_id"`
- MaskLength *int `xml:"mask_length"`
- ExportDir *string `xml:"export_dir"`
- Header *CgrXmlCfgCdrHeader `xml:"export_template>header"`
- Content *CgrXmlCfgCdrContent `xml:"export_template>content"`
- Trailer *CgrXmlCfgCdrTrailer `xml:"export_template>trailer"`
-}
-
-// CDR header
-type CgrXmlCfgCdrHeader struct {
- XMLName xml.Name `xml:"header"`
- Fields []*XmlCfgCdrField `xml:"fields>field"`
-}
-
-// CDR content
-type CgrXmlCfgCdrContent struct {
- XMLName xml.Name `xml:"content"`
- Fields []*XmlCfgCdrField `xml:"fields>field"`
-}
-
-// CDR trailer
-type CgrXmlCfgCdrTrailer struct {
- XMLName xml.Name `xml:"trailer"`
- Fields []*XmlCfgCdrField `xml:"fields>field"`
-}
-
-// Define a format for configuration file, one doc contains more configuration instances, identified by section, type and id
-type CgrXmlCfgDocument struct {
- XMLName xml.Name `xml:"document"`
- Type string `xml:"type,attr"`
- Configurations []*CgrXmlConfiguration `xml:"configuration"`
- cdrcs map[string]*CgrXmlCdrcCfg
- cdres map[string]*CgrXmlCdreCfg // Cahe cdrexporter instances, key will be the ID
-}
-
-// Storage for raw configuration
-type CgrXmlConfiguration struct {
- XMLName xml.Name `xml:"configuration"`
- Section string `xml:"section,attr"`
- Id string `xml:"id,attr"`
- RawConfig []byte `xml:",innerxml"` // Used to store the configuration struct, as raw so we can store different types
-}
-
-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
-}
-
-func (xmlCfg *CgrXmlCfgDocument) cacheAll() error {
- for _, cacheFunc := range []func() error{xmlCfg.cacheCdrcCfgs, xmlCfg.cacheCdreCfgs} {
- if err := cacheFunc(); err != nil {
- return err
- }
- }
- return nil
-}
-
-// 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)
- }
- xmlCfg.cdrcs[cfgInst.Id] = cdrcCfg
- }
- return nil
-}
-
-// Avoid building from raw config string always, so build cache here
-func (xmlCfg *CgrXmlCfgDocument) cacheCdreCfgs() error {
- xmlCfg.cdres = make(map[string]*CgrXmlCdreCfg)
- for _, cfgInst := range xmlCfg.Configurations {
- if cfgInst.Section != utils.CDRE {
- continue
- }
- cdreCfg := new(CgrXmlCdreCfg)
- if err := xml.Unmarshal(cfgInst.rawConfigElement(), cdreCfg); err != nil {
- return err
- } else if cdreCfg == nil {
- return fmt.Errorf("Could not unmarshal CgrXmlCdreCfg: %s", cfgInst.Id)
- }
- xmlCfg.cdres[cfgInst.Id] = cdreCfg
- }
- return nil
-}
-
-// Return instances or filtered instance of cdrefw configuration
-func (xmlCfg *CgrXmlCfgDocument) GetCdreCfgs(instName string) map[string]*CgrXmlCdreCfg {
- if len(instName) != 0 {
- if cfg, hasIt := xmlCfg.cdres[instName]; !hasIt {
- return nil
- } else {
- return map[string]*CgrXmlCdreCfg{instName: cfg}
- }
- }
- return xmlCfg.cdres
-}
-
-// Return instances or filtered instance of cdrc configuration
-func (xmlCfg *CgrXmlCfgDocument) GetCdrcCfgs(instName string) map[string]*CgrXmlCdrcCfg {
- if len(instName) != 0 {
- if cfg, hasIt := xmlCfg.cdrcs[instName]; !hasIt {
- return nil
- } else {
- return map[string]*CgrXmlCdrcCfg{instName: cfg} // Filtered
- }
- }
- return xmlCfg.cdrcs // Unfiltered
-}
diff --git a/data/conf/cgrates.cfg b/data/conf/cgrates.cfg
deleted file mode 100644
index efe8530fa..000000000
--- a/data/conf/cgrates.cfg
+++ /dev/null
@@ -1,182 +0,0 @@
-# Real-time Charging System for Telecom & ISP environments
-# Copyright (C) ITsysCOM GmbH
-#
-# This file contains the default configuration hardcoded into CGRateS.
-# This is what you get when you load CGRateS with an empty configuration file.
-
-[global]
-# ratingdb_type = redis # Rating subsystem database: .
-# ratingdb_host = 127.0.0.1 # Rating subsystem database host address.
-# ratingdb_port = 6379 # Rating subsystem port to reach the database.
-# ratingdb_name = 10 # Rating subsystem database name to connect to.
-# ratingdb_user = # Rating subsystem username to use when connecting to database.
-# ratingdb_passwd = # Rating subsystem password to use when connecting to database.
-# accountdb_type = redis # Accounting subsystem database: .
-# accountdb_host = 127.0.0.1 # Accounting subsystem database host address.
-# accountdb_port = 6379 # Accounting subsystem port to reach the database.
-# accountdb_name = 11 # Accounting subsystem database name to connect to.
-# accountdb_user = # Accounting subsystem username to use when connecting to database.
-# accountdb_passwd = # Accounting subsystem password to use when connecting to database.
-# stordb_type = mysql # Stor database type to use:
-# stordb_host = 127.0.0.1 # The host to connect to. Values that start with / are for UNIX domain sockets.
-# stordb_port = 3306 # The port to reach the stordb.
-# stordb_name = cgrates # The name of the log database to connect to.
-# stordb_user = cgrates # Username to use when connecting to stordb.
-# stordb_passwd = CGRateS.org # Password to use when connecting to stordb.
-# stordb_max_open_conns = 0 # Maximum database connections opened
-# stordb_max_idle_conns = -10 # Maximum database connections idle
-# dbdata_encoding = msgpack # The encoding used to store object data in strings:
-# rpc_json_listen = 127.0.0.1:2012 # RPC JSON listening address
-# rpc_gob_listen = 127.0.0.1:2013 # RPC GOB listening address
-# http_listen = 127.0.0.1:2080 # HTTP listening address
-# default_reqtype = rated # Default request type to consider when missing from requests: <""|prepaid|postpaid|pseudoprepaid|rated>.
-# default_category = call # Default Type of Record to consider when missing from requests.
-# default_tenant = cgrates.org # Default Tenant to consider when missing from requests.
-# default_subject = cgrates # Default rating Subject to consider when missing from requests.
-# rounding_decimals = 10 # System level precision for floats
-# http_skip_tls_veify = false # If enabled Http Client will accept any TLS certificate
-# tpexport_dir = /var/log/cgrates/tpe # Path towards export folder for offline Tariff Plans
-# xmlcfg_path = # Path towards additional config defined in xml file
-
-[balancer]
-# enabled = false # Start Balancer service: .
-
-[rater]
-# enabled = false # Enable Rater service: .
-# balancer = # Register to Balancer as worker: <""|internal|127.0.0.1:2013>.
-
-[scheduler]
-# enabled = false # Starts Scheduler service: .
-
-[cdrs]
-# enabled = false # Start the CDR Server service: .
-# extra_fields = # Extra fields to store in CDRs for non-generic CDRs
-# mediator = # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
-# cdrstats = # Address where to reach the cdrstats service. Empty to disable stats gathering from raw CDRs <""|internal|x.y.z.y:1234>
-# store_disable = false # When true, CDRs will not longer be saved in stordb, useful for cdrstats only scenario
-
-[cdre]
-# cdr_format = csv # Exported CDRs format
-# data_usage_multiply_factor = 0.0 # Multiply data usage before export (eg: convert from KBytes to Bytes)
-# cost_multiply_factor = 0.0 # Multiply cost before export (0.0 to disable), eg: add VAT
-# cost_rounding_decimals = -1 # Rounding decimals for Cost values. -1 to disable rounding
-# cost_shift_digits = 0 # Shift digits in the cost on export (eg: convert from EUR to cents)
-# mask_destination_id = # Destination id containing called addresses to be masked on export
-# mask_length = 0 # Length of the destination suffix to be masked
-# export_dir = /var/log/cgrates/cdre # Path where the exported CDRs will be placed
-# export_template = cgrid,mediation_runid,tor,accid,reqtype,direction,tenant,category,account,subject,destination,setup_time,answer_time,usage,cost
- # Exported fields template <""|fld1,fld2|*xml:instance_name>
-[cdrc]
-# enabled = false # Enable CDR client functionality
-# cdrs = internal # Address where to reach CDR server.
-# run_delay = 0 # Sleep interval in seconds between consecutive runs, 0 to use automation via inotify
-# cdr_format = csv # CDR file format .
-# field_separator = , # Separator used in case of csv files. One character only supported and needs to be right after equal sign
-# data_usage_multiply_factor = 1 # Conversion factor for data usage
-# cdr_in_dir = /var/log/cgrates/cdrc/in # Absolute path towards the directory where the CDRs are stored.
-# cdr_out_dir = /var/log/cgrates/cdrc/out # Absolute path towards the directory where processed CDRs will be moved.
-# cdr_source_id = csv # Free form field, tag identifying the source of the CDRs within CGRS database.
-# tor_field = 2 # TypeOfRecord field identifier. Use index number in case of .csv cdrs.
-# accid_field = 3 # Accounting id field identifier. Use index number in case of .csv cdrs.
-# reqtype_field = 4 # Request type field identifier. Use index number in case of .csv cdrs.
-# direction_field = 5 # Direction field identifier. Use index numbers in case of .csv cdrs.
-# tenant_field = 6 # Tenant field identifier. Use index numbers in case of .csv cdrs.
-# category_field = 7 # Type of Record field identifier. Use index numbers in case of .csv cdrs.
-# account_field = 8 # Account field identifier. Use index numbers in case of .csv cdrs.
-# subject_field = 9 # Subject field identifier. Use index numbers in case of .csv CDRs.
-# destination_field = 10 # Destination field identifier. Use index numbers in case of .csv cdrs.
-# setup_time_field = 11 # Setup time field identifier. Use index numbers in case of .csv cdrs.
-# answer_time_field = 12 # Answer time field identifier. Use index numbers in case of .csv cdrs.
-# usage_field = 13 # Usage field identifier. Use index numbers in case of .csv cdrs.
-# extra_fields = # Extra fields identifiers. For .csv, format: :[...,:]
-
-[mediator]
-# enabled = false # Starts Mediator service: .
-# reconnects = 3 # Number of reconnects to rater/cdrs before giving up.
-# rater = internal # Address where to reach the Rater:
-# cdrstats = # Address where to reach the cdrstats service. Empty to disable stats gathering out of mediated CDRs <""|internal|x.y.z.y:1234>
-# store_disable = false # When true, CDRs will not longer be saved in stordb, useful for cdrstats only scenario
-
-
-[cdrstats]
-# enabled = false # Starts the cdrstats service:
-# queue_length = 50 # Number of items in the stats buffer
-# time_window = 1h # Will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow
-# metrics = ASR, ACD, ACC # Stat metric ids to build
-# setup_interval = # Filter on CDR SetupTime
-# tors = # Filter on CDR TOR fields
-# cdr_hosts= # Filter on CDR CdrHost fields
-# cdr_sources = # Filter on CDR CdrSource fields
-# req_types = # Filter on CDR ReqType fields
-# directions = # Filter on CDR Direction fields
-# tenants = # Filter on CDR Tenant fields
-# categories = # Filter on CDR Category fields
-# accounts = # Filter on CDR Account fields
-# subjects = # Filter on CDR Subject fields
-# destination_prefixes = # Filter on CDR Destination prefixes
-# usage_interval = # Filter on CDR Usage
-# mediation_run_ids = # Filter on CDR MediationRunId fields
-# rated_accounts = # Filter on CDR RatedAccount fields
-# rated_subjects = # Filter on CDR RatedSubject fields
-# cost_intervals = # Filter on CDR Cost
-
-[session_manager]
-# enabled = false # Starts SessionManager service:
-# switch_type = freeswitch # Defines the type of switch behind:
-# rater = internal # Address where to reach the Rater <""|internal|127.0.0.1:2013>
-# cdrs = # Address where to reach CDR Server, empty to disable CDR capturing <""|internal|127.0.0.1:2013>
-# reconnects = 3 # Number of reconnects to rater/cdrs before giving up.
-# debit_interval = 10 # Interval to perform debits on.
-# min_call_duration = 0s # Only authorize calls with allowed duration bigger than this
-# max_call_duration = 3h # Maximum call duration a prepaid call can last
-
-[freeswitch]
-# server = 127.0.0.1:8021 # Adress where to connect to FreeSWITCH socket.
-# passwd = ClueCon # FreeSWITCH socket password.
-# reconnects = 5 # Number of attempts on connect failure.
-# min_dur_low_balance = 5s # Threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval)
-# low_balance_ann_file = # File to be played when low balance is reached for prepaid calls
-# empty_balance_context = # If defined, prepaid calls will be transfered to this context on empty balance
-# empty_balance_ann_file = # File to be played before disconnecting prepaid calls on empty balance (applies only if no context defined)
-# cdr_extra_fields = # Extra fields to store in CDRs in case of processing them
-
-[kamailio]
-# evapi_addr = 127.0.0.1:8448 # Address of the kamailio evapi server
-# reconnects = 3 # Number of attempts on connect failure.
-
-[opensips]
-# listen_udp = 127.0.0.1:2020 # Address where to listen for datagram events coming from OpenSIPS
-# mi_addr = 127.0.0.1:8020 # Adress where to reach OpenSIPS mi_datagram module
-# events_subscribe_interval = 60s # Automatic events subscription to OpenSIPS, 0 to disable it
-# reconnects = 3 # Number of attempts on connect failure.
-
-[derived_charging]
-# run_ids = # Identifiers of additional sessions control.
-# run_filters = # List of cdr field filters for each run.
-# reqtype_fields = # Name of request type fields to be used during additional sessions control <""|*default|field_name>.
-# direction_fields = # Name of direction fields to be used during additional sessions control <""|*default|field_name>.
-# tenant_fields = # Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
-# category_fields = # Name of tor fields to be used during additional sessions control <""|*default|field_name>.
-# account_fields = # Name of account fields to be used during additional sessions control <""|*default|field_name>.
-# subject_fields = # Name of fields to be used during additional sessions control <""|*default|field_name>.
-# destination_fields = # Name of destination fields to be used during additional sessions control <""|*default|field_name>.
-# setup_time_fields = # Name of setup_time fields to be used during additional sessions control <""|*default|field_name>.
-# answer_time_fields = # Name of answer_time fields to be used during additional sessions control <""|*default|field_name>.
-# usage_fields = # Name of usage fields to be used during additional sessions control <""|*default|field_name>.
-# combined_chargers = true # Combine accounts specific derived_chargers with server configured ones .
-
-[history_server]
-# enabled = false # Starts History service: .
-# history_dir = /var/log/cgrates/history # Location on disk where to store history files.
-# save_interval = 1s # Interval to save changed cache into .git archive
-
-[history_agent]
-# enabled = false # Starts History as a client: .
-# server = internal # Address where to reach the master history server:
-
-[mailer]
-# server = localhost # The server to use when sending emails out
-# auth_user = cgrates # Authenticate to email server using this user
-# auth_passwd = CGRateS.org # Authenticate to email server with this password
-# from_address = cgr-mailer@localhost.localdomain # From address used when sending emails out
-
diff --git a/data/conf/cgrates.json b/data/conf/cgrates/cgrates.json
similarity index 100%
rename from data/conf/cgrates.json
rename to data/conf/cgrates/cgrates.json
diff --git a/data/conf/samples/apier/apier.json b/data/conf/samples/apier/apier.json
new file mode 100644
index 000000000..6bb268430
--- /dev/null
+++ b/data/conf/samples/apier/apier.json
@@ -0,0 +1,31 @@
+{
+// CGRateS Configuration file
+//
+// Used in apier_local_tests
+// Starts rater, cdrs and mediator connecting over internal channel
+
+"rater": {
+ "enabled": true, // enable Rater service:
+},
+
+"scheduler": {
+ "enabled": true, // start Scheduler service:
+},
+
+"cdrs": {
+ "enabled": true, // start the CDR Server service:
+ "mediator": "internal", // address where to reach the Mediator. Empty for disabling mediation. <""|internal>
+},
+
+"cdre": {
+ "*default": {
+ "export_dir": "/tmp/cgrates/cdr/cdrexport/csv", // path where the exported CDRs will be placed
+ }
+},
+
+"mediator": {
+ "enabled": true, // starts Mediator service: .
+
+},
+
+}
\ No newline at end of file
diff --git a/data/conf/samples/mediator1/mediator_test1.json b/data/conf/samples/mediator1/mediator_test1.json
new file mode 100644
index 000000000..f446edd2a
--- /dev/null
+++ b/data/conf/samples/mediator1/mediator_test1.json
@@ -0,0 +1,30 @@
+{
+// CGRateS Configuration file
+//
+// Used in mediator_local_test
+// Starts rater, cdrs and mediator connecting over internal channel
+
+"rater": {
+ "enabled": true, // enable Rater service:
+},
+
+"scheduler": {
+ "enabled": true, // start Scheduler service:
+},
+
+"cdrs": {
+ "enabled": true, // start the CDR Server service:
+ "mediator": "internal", // address where to reach the Mediator. Empty for disabling mediation. <""|internal>
+},
+
+"cdre": {
+ "*default": {
+ "export_dir": "/tmp/cgrates/cdr/cdrexport/csv", // path where the exported CDRs will be placed
+ }
+},
+
+"mediator": {
+ "enabled": true, // starts Mediator service: .
+},
+
+}
\ No newline at end of file
diff --git a/data/conf/samples/mediator_test1.cfg b/data/conf/samples/mediator_test1.cfg
deleted file mode 100644
index e35edb524..000000000
--- a/data/conf/samples/mediator_test1.cfg
+++ /dev/null
@@ -1,38 +0,0 @@
-# CGRateS Configuration file
-#
-# Used in mediator_local_test
-# Starts rater, cdrs and mediator connecting over internal channel
-
-[rater]
-enabled = true # Enable RaterCDRSExportPath service: .
-
-[scheduler]
-enabled = true # Starts Scheduler service: .
-
-[cdrs]
-enabled = true # Start the CDR Server service: .
-mediator = internal # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
-
-[cdre]
-export_dir = /tmp/cgrates/cdr/cdrexport/csv # Path where the exported CDRs will be placed
-
-[mediator]
-enabled = true # Starts Mediator service: .
-rater = internal # Address where to reach the Rater:
-cdrstats =
-
-[derived_charging]
-run_ids = run2 # Identifiers of additional sessions control.
-reqtype_fields = *default # Name of request type fields to be used during additional sessions control <""|*default|field_name>.
-direction_fields = *default # Name of direction fields to be used during additional sessions control <""|*default|field_name>.
-tenant_fields = *default # Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
-category_fields = *default # Name of tor fields to be used during additional sessions control <""|*default|field_name>.
-account_fields = ^dc2 # Name of account fields to be used during additional sessions control <""|*default|field_name>.
-subject_fields = ^dc2 # Name of fields to be used during additional sessions control <""|*default|field_name>.
-destination_fields = *default # Name of destination fields to be used during additional sessions control <""|*default|field_name>.
-setup_time_fields = *default # Name of setup_time fields to be used during additional sessions control <""|*default|field_name>.
-answer_time_fields = *default # Name of answer_time fields to be used during additional sessions control <""|*default|field_name>.
-usage_fields = *default # Name of usage fields to be used during additional sessions control <""|*default|field_name>.
-
-
-
diff --git a/data/conf/samples/multiplecdrc/multiplecdrc_fwexport.json b/data/conf/samples/multiplecdrc/multiplecdrc_fwexport.json
new file mode 100644
index 000000000..d06eda407
--- /dev/null
+++ b/data/conf/samples/multiplecdrc/multiplecdrc_fwexport.json
@@ -0,0 +1,125 @@
+{
+// CGRateS Configuration file
+//
+// Used in mediator_local_test
+// Starts rater, cdrs and mediator connecting over internal channel
+
+"rater": {
+ "enabled": true, // enable Rater service:
+},
+
+"scheduler": {
+ "enabled": true, // start Scheduler service:
+},
+
+"cdrs": {
+ "enabled": true, // start the CDR Server service:
+ "mediator": "internal", // address where to reach the Mediator. Empty for disabling mediation. <""|internal>
+},
+
+"cdrc": {
+ "CDRC-CSV1": {
+ "enabled": true, // enable CDR client functionality
+ "cdr_in_dir": "/tmp/cgrates/cdrc1/in", // absolute path towards the directory where the CDRs are stored
+ "cdr_out_dir": "/tmp/cgrates/cdrc1/out", // absolute path towards the directory where processed CDRs will be moved
+ "cdr_source_id": "csv1", // free form field, tag identifying the source of the CDRs within CDRS database
+ },
+ "CDRC-CSV2": {
+ "enabled": true, // enable CDR client functionality
+ "cdr_in_dir": "/tmp/cgrates/cdrc2/in", // absolute path towards the directory where the CDRs are stored
+ "cdr_out_dir": "/tmp/cgrates/cdrc2/out", // absolute path towards the directory where processed CDRs will be moved
+ "cdr_source_id": "csv2", // free form field, tag identifying the source of the CDRs within CDRS database
+ "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
+ {"cdr_field_id": "tor", "value": "~7:s/^(voice|data|sms)$/*$1/"},
+ {"cdr_field_id": "accid", "value": "0"},
+ {"cdr_field_id": "reqtype", "value": "^rated"},
+ {"cdr_field_id": "direction", "value": "^*out"},
+ {"cdr_field_id": "tenant", "value": "^cgrates.org"},
+ {"cdr_field_id": "category", "value": "~7:s/^voice$/call/"},
+ {"cdr_field_id": "account", "value": "3"},
+ {"cdr_field_id": "subject", "value": "3"},
+ {"cdr_field_id": "destination", "value": "~5:s/^0([1-9]\\d+)$/+49$1/"},
+ {"cdr_field_id": "setup_time", "value": "1"},
+ {"cdr_field_id": "answer_time", "value": "1"},
+ {"cdr_field_id": "usage", "value": "~9:s/^(\\d+)$/${1}s/"},
+ ],
+ },
+ "CDRC-CSV3": {
+ "enabled": true, // enable CDR client functionality
+ "field_separator": ";", // separator used in case of csv files
+ "cdr_in_dir": "/tmp/cgrates/cdrc3/in", // absolute path towards the directory where the CDRs are stored
+ "cdr_out_dir": "/tmp/cgrates/cdrc3/out", // absolute path towards the directory where processed CDRs will be moved
+ "cdr_source_id": "csv3", // free form field, tag identifying the source of the CDRs within CDRS database
+ "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
+ {"cdr_field_id": "tor", "value": "^*voice"},
+ {"cdr_field_id": "accid", "value": "~3:s/^(\\d{2})\\.(\\d{2})\\.(\\d{4})\\s{2}(\\d{2}):(\\d{2}):(\\d{2})$/$1$2$3$4$5$6/"},
+ {"cdr_field_id": "reqtype", "value": "^rated"},
+ {"cdr_field_id": "direction", "value": "^*out"},
+ {"cdr_field_id": "tenant", "value": "^cgrates.org"},
+ {"cdr_field_id": "category", "value": "^call"},
+ {"cdr_field_id": "account", "value": "~0:s/^([1-9]\\d+)$/+$1/"},
+ {"cdr_field_id": "subject", "value": "~0:s/^([1-9]\\d+)$/+$1/"},
+ {"cdr_field_id": "destination", "value": "~1:s/^([1-9]\\d+)$/+$1/"},
+ {"cdr_field_id": "setup_time", "value": "4"},
+ {"cdr_field_id": "answer_time", "value": "4"},
+ {"cdr_field_id": "usage", "value": "~6:s/^(\\d+)$/${1}s/"},
+ ],
+ }
+},
+
+"mediator": {
+ "enabled": true, // starts Mediator service: .
+},
+
+"cdre": {
+ "CDRE-FW1": {
+ "cdr_format": "fwv",
+ "field_separator": "",
+ "header_fields": [
+ {"tag": "ToR", "type": "constant", "value": "10", "width": 2},
+ {"tag": "Filler1", "type": "filler", "width": 3},
+ {"tag": "FileType", "type": "constant", "value": "SIP", "width": 3},
+ {"tag": "FileSeqNr", "type": "metatag", "value": "export_id", "padding": "zeroleft", "width": 5},
+ {"tag": "LastCdr", "type": "metatag", "value": "last_cdr_atime", "layout": "020106150405", "width": 12},
+ {"tag": "FileCreationfTime", "type": "metatag", "value": "time_now", "layout": "020106150405", "width": 12},
+ {"tag": "FileVersion", "type": "constant", "value": "01", "width": 2},
+ {"tag": "Filler2", "type": "filler", "width": 105},
+ ], // template of the exported header fields
+ "content_fields": [ // template of the exported content fields
+ {"tag": "ToR", "type": "constant", "value": "20", "width": 2},
+ {"tag": "Subject", "type": "cdrfield", "value": "subject", "width": 12, "padding": "right", "mandatory": true},
+ {"tag": "ConnectionNumber", "type": "constant", "value": "00000", "width": 5},
+ {"tag": "CallerId", "type": "cdrfield", "value": "~callerid:s/\\+(\\d+)/00$1/", "strip": "xright", "width": 15, "padding": "right"},
+ {"tag": "Destination", "type": "cdrfield", "value": "~destination:s/^\\+311400(\\d+)/$1/:s/^\\+311412\\d\\d112/112/:s/^\\+31(\\d+)/0$1/:s/^\\+(\\d+)/00$1/",
+ "strip": "xright", "width": 24, "padding": "right", "mandatory": true},
+ {"tag": "TypeOfService", "type": "constant", "value": "00", "width": 2},
+ {"tag": "ServiceId", "type": "constant", "value": "11", "width": 4, "padding": "right"},
+ {"tag": "AnswerTime", "type": "cdrfield", "value": "answer_time", "layout": "020106150405", "width": 12, "mandatory": true},
+ {"tag": "Usage", "type": "cdrfield", "value": "usage", "layout": "seconds", "width": 6, "padding": "right", "mandatory": true},
+ {"tag": "DataCounter", "type": "filler", "width": 6},
+ {"tag": "VatCode", "type": "constant", "value": "1", "width": 1},
+ {"tag": "NetworkId", "type": "constant", "value": "S1", "width": 2},
+ {"tag": "DestinationSubId", "type": "cdrfield", "value": "~cost_details:s/MatchedDestId:.+_(\\w{5})/$1/:s/(\\w{6})/$1/", "width": 5},
+ {"tag": "NetworkSubtype", "type": "constant", "value": "3", "width": 1, "padding": "left"},
+ {"tag": "CgrId", "type": "cdrfield", "value": "cgrid", "strip": "xleft", "width": 16, "padding": "right", "mandatory": true},
+ {"tag": "FillerVolume1", "type": "filler", "width": 8},
+ {"tag": "FillerVolume2", "type": "filler", "width": 8},
+ {"tag": "DestinationSubId", "type": "cdrfield", "value": "~cost_details:s/MatchedDestId:.+_(\\w{5})/$1/:s/(\\w{6})/$1/", "width": 5},
+ {"tag": "Cost", "type": "cdrfield", "value": "cost", "padding": "zeroleft", "width": 9},
+ {"tag": "MaskDestination", "type": "metatag", "value": "mask_destination", "width": 1},
+ ],
+ "trailer_fields": [
+ {"tag": "ToR", "type": "constant", "value": "90", "width": 2},
+ {"tag": "Filler1", "type": "filler", "width": 3},
+ {"tag": "FileType", "type": "constant", "value": "SIP", "width": 3},
+ {"tag": "FileSeqNr", "type": "metatag", "value": "export_id", "padding": "zeroleft", "width": 5},
+ {"tag": "TotalRecords", "type": "metatag", "value": "cdrs_number", "padding": "zeroleft", "width": 6},
+ {"tag": "TotalDuration", "type": "metatag", "value": "cdrs_duration", "padding": "zeroleft", "width": 8},
+ {"tag": "FirstCdrTime", "type": "metatag", "value": "first_cdr_atime", "layout": "020106150405", "width": 12},
+ {"tag": "LastCdrTime", "type": "metatag", "value": "last_cdr_atime", "layout": "020106150405", "width": 12},
+ {"tag": "Filler1", "type": "filler", "width": 93},
+ ], // template of the exported trailer fields
+ }
+},
+
+}
\ No newline at end of file
diff --git a/data/conf/samples/multiplecdrc_fwexport.cfg b/data/conf/samples/multiplecdrc_fwexport.cfg
deleted file mode 100644
index 3961e8609..000000000
--- a/data/conf/samples/multiplecdrc_fwexport.cfg
+++ /dev/null
@@ -1,28 +0,0 @@
-# Real-time Charging System for Telecom & ISP environments
-# Copyright (C) 2012-2014 ITsysCOM GmbH
-
-[global]
-xmlcfg_path = /usr/share/cgrates/conf/samples/multiplecdrc_fwexport.xml
-
-[rater]
-enabled = true # Enable RaterCDRSExportPath service: .
-
-[scheduler]
-enabled = true # Starts Scheduler service: .
-
-[cdrs]
-enabled = true # Start the CDR Server service: .
-mediator = internal # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
-
-[cdre]
-export_dir = /tmp/cgrates/cdr/cdre/csv # Path where the exported CDRs will be placed
-export_template = *xml:CDRE-FW1
-
-[cdrc]
-enabled = true
-cdr_in_dir = /tmp/cgrates/cdrc1/in # Absolute path towards the directory where the CDRs are stored.
-cdr_out_dir =/tmp/cgrates/cdrc1/out # Absolute path towards the directory where processed CDRs will be moved.
-cdr_source_id = csv1 # Free form field, tag identifying the source of the CDRs within CGRS database.
-
-[mediator]
-enabled = true # Starts Mediator service: .
\ No newline at end of file
diff --git a/data/conf/samples/multiplecdrc_fwexport.xml b/data/conf/samples/multiplecdrc_fwexport.xml
deleted file mode 100644
index 6f911c041..000000000
--- a/data/conf/samples/multiplecdrc_fwexport.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
- true
- internal
- csv
- ,
- 0
- /tmp/cgrates/cdrc2/in
- /tmp/cgrates/cdrc2/out
- csv2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
- internal
- csv
- ;
- 0
- /tmp/cgrates/cdrc3/in
- /tmp/cgrates/cdrc3/out
- csv3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- fwv
- 0.0
- 0.0
- 0
- MASKED_DESTINATIONS
- 0
- /var/log/cgrates/cdre
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/data/conf/samples/tutorial/tutorial.json b/data/conf/samples/tutorial/tutorial.json
new file mode 100644
index 000000000..cfd9fe15b
--- /dev/null
+++ b/data/conf/samples/tutorial/tutorial.json
@@ -0,0 +1,31 @@
+{
+// CGRateS Configuration file
+//
+// Used in mediator_local_test
+// Starts rater, cdrs and mediator connecting over internal channel
+
+"rater": {
+ "enabled": true, // enable Rater service:
+},
+
+"scheduler": {
+ "enabled": true, // start Scheduler service:
+},
+
+"cdrs": {
+ "enabled": true, // start the CDR Server service:
+ "mediator": "internal", // address where to reach the Mediator.
+},
+
+"cdre": {
+ "*default": {
+ "export_dir": "/tmp", // path where the exported CDRs will be placed
+ }
+},
+
+"mediator": {
+ "enabled": true, // starts Mediator service: .
+ "cdrstats": "internal",
+},
+
+}
\ No newline at end of file
diff --git a/data/conf/samples/tutorial_local_test.cfg b/data/conf/samples/tutorial_local_test.cfg
deleted file mode 100644
index 089506a5f..000000000
--- a/data/conf/samples/tutorial_local_test.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-# Real-time Charging System for Telecom & ISP environments
-# Copyright (C) ITsysCOM GmbH
-#
-# This file contains the default configuration hardcoded into CGRateS.
-# This is what you get when you load CGRateS with an empty configuration file.
-
-[rater]
-enabled = true # Enable RaterCDRSExportPath service: .
-
-[scheduler]
-enabled = true # Starts Scheduler service: .
-
-[cdrs]
-enabled = true # Start the CDR Server service: .
-mediator = internal # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
-
-[cdre]
-cdr_format = csv # Exported CDRs format
-export_dir = /tmp # Path where the exported CDRs will be placed
-
-[mediator]
-enabled = true # Starts Mediator service: .
-cdrstats = internal
-
-[cdrstats]
-enabled = true # Starts the cdrstats service:
\ No newline at end of file
diff --git a/data/scripts/pkg/debian/rules b/data/scripts/pkg/debian/rules
index b26ea2e9d..aa8b689b8 100755
--- a/data/scripts/pkg/debian/rules
+++ b/data/scripts/pkg/debian/rules
@@ -25,8 +25,7 @@ binary-arch: clean
cd $(SRCDIR) && go install
mkdir -p $(PKGDIR)/usr/bin
cp $(GOPATH)/bin/cgr-* $(PKGDIR)/usr/bin/
- mkdir -p $(PKGDIR)/etc/cgrates
- cp $(SRCDIR)/data/conf/cgrates.cfg $(PKGDIR)/etc/cgrates/
+ cp -r $(SRCDIR)/data/conf/cgrates $(PKGDIR)/etc/
mkdir -p $(PKGDIR)/usr/share/cgrates
cp -r $(SRCDIR)/data/* $(PKGDIR)/usr/share/cgrates/
mkdir -p $(PKGDIR)/var/log/cgrates/cdrc/in
diff --git a/engine/fscdr_test.go b/engine/fscdr_test.go
index 1b2dd1c83..f69cd5aff 100644
--- a/engine/fscdr_test.go
+++ b/engine/fscdr_test.go
@@ -46,7 +46,10 @@ func TestFirstNonEmpty(t *testing.T) {
}
func TestCDRFields(t *testing.T) {
- cfg, _ = config.NewDefaultCGRConfig()
+ cfg, err = config.NewDefaultCGRConfig()
+ if err != nil {
+ t.Error(err)
+ }
cfg.CDRSExtraFields = []*utils.RSRField{&utils.RSRField{Id: "sip_user_agent"}}
fsCdr, err := NewFSCdr(body)
if err != nil {
@@ -108,10 +111,9 @@ func TestSearchReplaceInExtraFields(t *testing.T) {
}
func TestDDazRSRExtraFields(t *testing.T) {
- eFieldsCfg := []byte(`[cdrs]
-extra_fields = ~effective_caller_id_number:s/(\d+)/+$1/
-
-`)
+ eFieldsCfg := `{"cdrs": {
+ "extra_fields": ["~effective_caller_id_number:s/(\\d+)/+$1/"],
+},}`
simpleJsonCdr := []byte(`{
"core-uuid": "feef0b51-7fdf-4c4a-878e-aff233752de2",
"channel_data": {
@@ -144,7 +146,7 @@ extra_fields = ~effective_caller_id_number:s/(\d+)/+$1/
}
}`)
var err error
- cfg, err = config.NewCGRConfigFromBytes(eFieldsCfg)
+ cfg, err = config.NewCGRConfigFromJsonString(eFieldsCfg)
if err != nil {
t.Error("Could not parse the config", err.Error())
} else if !reflect.DeepEqual(cfg.CDRSExtraFields, []*utils.RSRField{&utils.RSRField{Id: "effective_caller_id_number",
diff --git a/engine/handler_derivedcharging.go b/engine/handler_derivedcharging.go
index 6178d2d7d..44fc5d98c 100644
--- a/engine/handler_derivedcharging.go
+++ b/engine/handler_derivedcharging.go
@@ -19,17 +19,18 @@ along with this program. If not, see
package engine
import (
- "github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
-// Transparently handles merging between storage data and configuration, useful as local handler
-func HandleGetDerivedChargers(acntStorage AccountingStorage, cfg *config.CGRConfig, attrs utils.AttrDerivedChargers) (utils.DerivedChargers, error) {
+// Handles retrieving of DerivedChargers profile based on longest match from AccountingDb
+func HandleGetDerivedChargers(acntStorage AccountingStorage, attrs utils.AttrDerivedChargers) (utils.DerivedChargers, error) {
var dcs utils.DerivedChargers
- var err error
strictKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, attrs.Category, attrs.Account, attrs.Subject)
anySubjKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, attrs.Category, attrs.Account, utils.ANY)
- for _, dcKey := range []string{strictKey, anySubjKey} {
+ anyAcntKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, attrs.Category, utils.ANY, utils.ANY)
+ anyCategKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, utils.ANY, utils.ANY, utils.ANY)
+ anyTenantKey := utils.DerivedChargersKey(attrs.Direction, utils.ANY, utils.ANY, utils.ANY, utils.ANY)
+ for _, dcKey := range []string{strictKey, anySubjKey, anyAcntKey, anyCategKey, anyTenantKey} {
if dcsDb, err := acntStorage.GetDerivedChargers(dcKey, false); err != nil && err.Error() != utils.ERR_NOT_FOUND {
return nil, err
} else if dcsDb != nil {
@@ -37,16 +38,5 @@ func HandleGetDerivedChargers(acntStorage AccountingStorage, cfg *config.CGRConf
break
}
}
- if dcs == nil {
- dcs = cfg.DerivedChargers
- return dcs, nil
- }
- if cfg.CombinedDerivedChargers {
- for _, cfgDc := range cfg.DerivedChargers {
- if dcs, err = dcs.Append(cfgDc); err != nil {
- return nil, err
- }
- }
- }
return dcs, nil
}
diff --git a/engine/handler_derivedcharging_test.go b/engine/handler_derivedcharging_test.go
index e212e05dd..43f65c92a 100644
--- a/engine/handler_derivedcharging_test.go
+++ b/engine/handler_derivedcharging_test.go
@@ -18,6 +18,7 @@ along with this program. If not, see
package engine
+/*
import (
"reflect"
"testing"
@@ -39,10 +40,11 @@ func init() {
acntDb.CacheAccounting(nil, nil, nil, nil)
}
+
// Accounting db has no DerivedChargers nor configured defaults
func TestHandleGetEmptyDC(t *testing.T) {
attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "test2", Subject: "test2"}
- if dcs, err := HandleGetDerivedChargers(acntDb, cfgDcT, attrs); err != nil {
+ if dcs, err := HandleGetDerivedChargers(acntDb, attrs); err != nil {
t.Error("Unexpected error", err.Error())
} else if !reflect.DeepEqual(dcs, cfgDcT.DerivedChargers) {
t.Error("Returned DerivedChargers not matching the configured ones")
@@ -91,3 +93,4 @@ func TestHandleGetStoredDC(t *testing.T) {
t.Error("Returned DerivedChargers not matching the configured ones")
}
}
+*/
diff --git a/engine/mediator_local_test.go b/engine/mediator_local_test.go
index e33b9b81c..a78ded552 100644
--- a/engine/mediator_local_test.go
+++ b/engine/mediator_local_test.go
@@ -1,6 +1,6 @@
/*
-Rating system designed to be used in VoIP Carriers World
-Copyright (C) 2012-2014 ITsysCOM
+Real-time Charging System 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
@@ -55,14 +55,14 @@ var httpClient *http.Client
var storDbType = flag.String("stordb_type", utils.MYSQL, "The type of the storDb database ")
var startDelay = flag.Int("delay_start", 300, "Number of miliseconds to it for rater to start and cache")
-var cfgPath = path.Join(*dataDir, "conf", "samples", "mediator_test1.cfg")
+var cfgPath = path.Join(*dataDir, "conf", "samples", "mediator_test1")
func TestMediInitRatingDb(t *testing.T) {
if !*testLocal {
return
}
var err error
- cgrCfg, err = config.NewCGRConfigFromFile(&cfgPath)
+ cgrCfg, err = config.NewCGRConfigFromFolder(cfgPath)
if err != nil {
t.Fatal("Got config error: ", err.Error())
}
diff --git a/engine/responder.go b/engine/responder.go
index efdd0af55..af0c81b1e 100644
--- a/engine/responder.go
+++ b/engine/responder.go
@@ -1,6 +1,6 @@
/*
Real-time Charging System for Telecom & ISP environments
-Copyright (C) 2012-2014 ITsysCOM GmbH
+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
@@ -221,7 +221,7 @@ func (rs *Responder) GetSessionRuns(ev utils.Event, sRuns *[]*SessionRun) error
func (rs *Responder) GetDerivedChargers(attrs utils.AttrDerivedChargers, dcs *utils.DerivedChargers) error {
// ToDo: Make it work with balancer if needed
- if dcsH, err := HandleGetDerivedChargers(accountingStorage, config.CgrConfig(), attrs); err != nil {
+ if dcsH, err := HandleGetDerivedChargers(accountingStorage, attrs); err != nil {
return err
} else if dcsH != nil {
*dcs = dcsH
diff --git a/engine/responder_test.go b/engine/responder_test.go
index e73b3b132..556efdcd2 100644
--- a/engine/responder_test.go
+++ b/engine/responder_test.go
@@ -1,6 +1,6 @@
/*
Real-time Charging System for Telecom & ISP environments
-Copyright (C) 2012-2014 ITsysCOM GmbH
+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
@@ -15,7 +15,6 @@ 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 engine
import (
@@ -29,15 +28,24 @@ import (
var rsponder *Responder
+func init() {
+ cfg, _ := config.NewDefaultCGRConfig()
+ config.SetCgrConfig(cfg)
+}
+
// Test internal abilites of GetDerivedChargers
func TestResponderGetDerivedChargers(t *testing.T) {
- cfg, _ := config.NewDefaultCGRConfig()
+
cfgedDC := utils.DerivedChargers{&utils.DerivedCharger{RunId: "responder1", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
CategoryField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", UsageField: "test"}}
- cfg.DerivedChargers = cfgedDC
- config.SetCgrConfig(cfg)
rsponder = &Responder{}
attrs := utils.AttrDerivedChargers{Tenant: "cgrates.org", Category: "call", Direction: "*out", Account: "responder_test", Subject: "responder_test"}
+ if err := accountingStorage.SetDerivedChargers(utils.DerivedChargersKey(utils.OUT, utils.ANY, utils.ANY, utils.ANY, utils.ANY), cfgedDC); err != nil {
+ t.Error(err)
+ }
+ if err := accountingStorage.CacheAccounting(nil, []string{}, []string{}, []string{}); err != nil {
+ t.Error(err)
+ }
var dcs utils.DerivedChargers
if err := rsponder.GetDerivedChargers(attrs, &dcs); err != nil {
t.Error("Unexpected error", err.Error())
@@ -47,7 +55,6 @@ func TestResponderGetDerivedChargers(t *testing.T) {
}
func TestGetDerivedMaxSessionTime(t *testing.T) {
- config.CgrConfig().CombinedDerivedChargers = false
testTenant := "vdf"
cdr := &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: "rated", Direction: "*out", Tenant: testTenant, Category: "call", Account: "dan", Subject: "dan",
@@ -88,7 +95,6 @@ func TestGetDerivedMaxSessionTime(t *testing.T) {
}
func TestGetSessionRuns(t *testing.T) {
- config.CgrConfig().CombinedDerivedChargers = false
testTenant := "vdf"
cdr := &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderId: 123, TOR: utils.VOICE, AccId: "dsafdsaf",
CdrHost: "192.168.1.1", CdrSource: "test", ReqType: "prepaid", Direction: "*out", Tenant: testTenant, Category: "call", Account: "dan2", Subject: "dan2",
diff --git a/engine/storage_utils.go b/engine/storage_utils.go
index f22b50434..aa68b38dd 100644
--- a/engine/storage_utils.go
+++ b/engine/storage_utils.go
@@ -41,12 +41,6 @@ func ConfigureRatingStorage(db_type, host, port, name, user, pass, marshaler str
host += ":" + port
}
d, err = NewRedisStorage(host, db_nb, pass, marshaler)
- /*
- // Add here as soon as interface implemented
- case utils.MONGO:
- d, err = NewMongoStorage(host, port, name, user, pass)
- db = d.(RatingStorage)
- */
default:
err = errors.New("unknown db")
}
diff --git a/general_tests/ddazmbl2_test.go b/general_tests/ddazmbl2_test.go
index 009321733..ccd91debf 100644
--- a/general_tests/ddazmbl2_test.go
+++ b/general_tests/ddazmbl2_test.go
@@ -163,7 +163,11 @@ func TestDebit2(t *testing.T) {
if acnt.BalanceMap[engine.MINUTES+engine.OUTBOUND][0].Value != 20 {
t.Error("Account does not have expected minutes in balance", acnt.BalanceMap[engine.MINUTES+engine.OUTBOUND][0].Value)
}
- if acnt.BalanceMap[engine.CREDIT+engine.OUTBOUND][0].Value != -0.01 {
- t.Error("Account does not have expected monetary balance", acnt.BalanceMap[engine.CREDIT+engine.OUTBOUND][0].Value)
+ for _, blnc := range acnt.BalanceMap[engine.CREDIT+engine.OUTBOUND] { // Test negative balance for default one
+ if blnc.Weight == 10 && blnc.Value != 0 {
+ t.Errorf("Balance with weight: %d, having value: %f ", blnc.Weight, blnc.Value)
+ } else if blnc.Weight == 0 && blnc.Value != -0.01 {
+ t.Errorf("Balance with weight: %d, having value: %f ", blnc.Weight, blnc.Value)
+ }
}
}
diff --git a/general_tests/multiplecdrc_local_test.go b/general_tests/multiplecdrc_local_test.go
index fb5e90b95..a01ce9bf8 100644
--- a/general_tests/multiplecdrc_local_test.go
+++ b/general_tests/multiplecdrc_local_test.go
@@ -44,11 +44,6 @@ var dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path h
var storDbType = flag.String("stordb_type", "mysql", "The type of the storDb database ")
var waitRater = flag.Int("wait_rater", 100, "Number of miliseconds to wait for rater to start and cache")
-func init() {
- cfgPath = path.Join(*dataDir, "conf", "samples", "multiplecdrc_fwexport.cfg")
- cfg, _ = config.NewCGRConfigFromFile(&cfgPath)
-}
-
func startEngine() error {
enginePath, err := exec.LookPath("cgr-engine")
if err != nil {
@@ -69,6 +64,14 @@ func stopEngine() error {
return nil
}
+func TestLoadConfig(t *testing.T) {
+ var err error
+ cfgPath = path.Join(*dataDir, "conf", "samples", "multiplecdrc")
+ if cfg, err = config.NewCGRConfigFromFolder(cfgPath); err != nil {
+ t.Error(err)
+ }
+}
+
func TestEmptyTables(t *testing.T) {
if !*testLocal {
return
@@ -97,7 +100,7 @@ func TestCreateCdrDirs(t *testing.T) {
if !*testLocal {
return
}
- for _, cdrcInst := range cfg.CdrcInstances {
+ for _, cdrcInst := range cfg.CdrcProfiles {
for _, dir := range []string{cdrcInst.CdrInDir, cdrcInst.CdrOutDir} {
if err := os.RemoveAll(dir); err != nil {
t.Fatal("Error removing folder: ", dir, err)
@@ -151,7 +154,7 @@ dbafe9c8614c785a65aabd116dd3959c3c56f7f7,default,*voice,dsafdsag,rated,*out,cgra
if err := ioutil.WriteFile(tmpFilePath, []byte(fileContent1), 0644); err != nil {
t.Fatal(err.Error)
}
- if err := os.Rename(tmpFilePath, path.Join(cfg.CdrcInstances[0].CdrInDir, fileName)); err != nil {
+ if err := os.Rename(tmpFilePath, path.Join(cfg.CdrcProfiles["CDRC-CSV1"].CdrInDir, fileName)); err != nil {
t.Fatal("Error moving file to processing directory: ", err)
}
}
@@ -169,7 +172,7 @@ func TestHandleCdr2File(t *testing.T) {
if err := ioutil.WriteFile(tmpFilePath, []byte(fileContent), 0644); err != nil {
t.Fatal(err.Error)
}
- if err := os.Rename(tmpFilePath, path.Join(*cfg.XmlCfgDocument.GetCdrcCfgs("CDRC-CSV2")["CDRC-CSV2"].CdrInDir, fileName)); err != nil {
+ if err := os.Rename(tmpFilePath, path.Join(cfg.CdrcProfiles["CDRC-CSV2"].CdrInDir, fileName)); err != nil {
t.Fatal("Error moving file to processing directory: ", err)
}
}
@@ -186,7 +189,7 @@ func TestHandleCdr3File(t *testing.T) {
if err := ioutil.WriteFile(tmpFilePath, []byte(fileContent), 0644); err != nil {
t.Fatal(err.Error)
}
- if err := os.Rename(tmpFilePath, path.Join(*cfg.XmlCfgDocument.GetCdrcCfgs("CDRC-CSV3")["CDRC-CSV3"].CdrInDir, fileName)); err != nil {
+ if err := os.Rename(tmpFilePath, path.Join(cfg.CdrcProfiles["CDRC-CSV3"].CdrInDir, fileName)); err != nil {
t.Fatal("Error moving file to processing directory: ", err)
}
}
diff --git a/general_tests/tutorial_local_test.go b/general_tests/tutorial_local_test.go
index c2a2e3640..2be1f7ac8 100644
--- a/general_tests/tutorial_local_test.go
+++ b/general_tests/tutorial_local_test.go
@@ -40,9 +40,9 @@ func TestInitCfg(t *testing.T) {
return
}
// Init config first
- tutCfgPath = path.Join(*dataDir, "conf", "samples", "tutorial_local_test.cfg")
+ tutCfgPath = path.Join(*dataDir, "conf", "samples", "tutorial")
var err error
- tutCfg, err = config.NewCGRConfigFromFile(&tutCfgPath)
+ tutCfg, err = config.NewCGRConfigFromFolder(tutCfgPath)
if err != nil {
t.Error(err)
}
diff --git a/hard_update_external_libs.py b/hard_update_external_libs.py
index 6962c5880..17edeb87a 100755
--- a/hard_update_external_libs.py
+++ b/hard_update_external_libs.py
@@ -4,8 +4,7 @@ import os
import os.path
from subprocess import call
-libs = ('code.google.com/p/goconf/conf',
- 'github.com/bmizerany/pq',
+libs = ('github.com/bmizerany/pq',
'github.com/ugorji/go/codec',
'labix.org/v2/mgo',
'github.com/cgrates/fsock',
diff --git a/update_external_libs.sh b/update_external_libs.sh
index efb14be02..49e2bb42a 100755
--- a/update_external_libs.sh
+++ b/update_external_libs.sh
@@ -1,5 +1,4 @@
#!/usr/bin/env sh
-go get -v -u code.google.com/p/goconf/conf
go get -v -u github.com/bmizerany/pq
go get -v -u github.com/ugorji/go/codec
go get -v -u labix.org/v2/mgo
diff --git a/utils/coreutils.go b/utils/coreutils.go
index e035887a0..8325a7e9b 100644
--- a/utils/coreutils.go
+++ b/utils/coreutils.go
@@ -355,3 +355,7 @@ func BoolPointer(b bool) *bool {
func StringSlicePointer(slc []string) *[]string {
return &slc
}
+
+func Float64SlicePointer(slc []float64) *[]float64 {
+ return &slc
+}
diff --git a/utils/rsrfield.go b/utils/rsrfield.go
index b3efc19ad..e89236f9e 100644
--- a/utils/rsrfield.go
+++ b/utils/rsrfield.go
@@ -1,6 +1,6 @@
/*
Real-time Charging System for Telecom & ISP environments
-Copyright (C) 2012-2014 ITsysCOM GmbH
+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
@@ -21,10 +21,14 @@ package utils
import (
"fmt"
"regexp"
+ "strconv"
"strings"
)
func NewRSRField(fldStr string) (*RSRField, error) {
+ if fldStrUnquoted, err := strconv.Unquote(fldStr); err == nil {
+ fldStr = fldStrUnquoted
+ }
if len(fldStr) == 0 {
return nil, nil
}
@@ -108,8 +112,16 @@ func ParseRSRFields(fldsStr, sep string) (RSRFields, error) {
return nil, nil
}
rulesSplt := strings.Split(fldsStr, sep)
- rsrFields := make(RSRFields, len(rulesSplt))
- for idx, ruleStr := range rulesSplt {
+ return ParseRSRFieldsFromSlice(rulesSplt)
+
+}
+
+func ParseRSRFieldsFromSlice(flds []string) (RSRFields, error) {
+ if len(flds) == 0 {
+ return nil, nil
+ }
+ rsrFields := make(RSRFields, len(flds))
+ for idx, ruleStr := range flds {
if rsrField, err := NewRSRField(ruleStr); err != nil {
return nil, err
} else {
@@ -117,6 +129,7 @@ func ParseRSRFields(fldsStr, sep string) (RSRFields, error) {
}
}
return rsrFields, nil
+
}
type RSRFields []*RSRField