func TestCdreCfgClone(t *testing.T) { cgrIdRsrs, _ := utils.ParseRSRFields("cgrid", utils.INFIELD_SEP) runIdRsrs, _ := utils.ParseRSRFields("mediation_runid", utils.INFIELD_SEP) emptyFields := []*CfgCdrField{} initContentFlds := []*CfgCdrField{ &CfgCdrField{Tag: "CgrId", Type: "*composed", FieldId: "cgrid", Value: cgrIdRsrs}, &CfgCdrField{Tag: "RunId", Type: "*composed", FieldId: "mediation_runid", Value: runIdRsrs}, } initCdreCfg := &CdreConfig{ CdrFormat: "csv", FieldSeparator: rune(','), DataUsageMultiplyFactor: 1.0, CostMultiplyFactor: 1.0, ExportDirectory: "/var/spool/cgrates/cdre", ContentFields: initContentFlds, } eClnContentFlds := []*CfgCdrField{ &CfgCdrField{Tag: "CgrId", Type: "*composed", FieldId: "cgrid", Value: cgrIdRsrs}, &CfgCdrField{Tag: "RunId", Type: "*composed", FieldId: "mediation_runid", Value: runIdRsrs}, } eClnCdreCfg := &CdreConfig{ CdrFormat: "csv", FieldSeparator: rune(','), DataUsageMultiplyFactor: 1.0, CostMultiplyFactor: 1.0, ExportDirectory: "/var/spool/cgrates/cdre", HeaderFields: emptyFields, ContentFields: eClnContentFlds, TrailerFields: emptyFields, } clnCdreCfg := initCdreCfg.Clone() if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { t.Errorf("Cloned result: %+v", clnCdreCfg) } initCdreCfg.DataUsageMultiplyFactor = 1024.0 if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { // MOdifying a field after clone should not affect cloned instance t.Errorf("Cloned result: %+v", clnCdreCfg) } initContentFlds[0].Tag = "Destination" if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { // MOdifying a field after clone should not affect cloned instance t.Errorf("Cloned result: %+v", clnCdreCfg) } clnCdreCfg.ContentFields[0].FieldId = "destination" if initCdreCfg.ContentFields[0].FieldId != "cgrid" { t.Error("Unexpected change of FieldId: ", initCdreCfg.ContentFields[0].FieldId) } }
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: <label_extrafield_1>:<index_extrafield_1> 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 }
func TestGetDateTimeFieldVal(t *testing.T) { cdreTst := new(CdrExporter) cdrTst := &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", 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, RunID: utils.DEFAULT_RUNID, Cost: 1.01, 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.CfgCdrField{Tag: "stop_time", Type: "cdrfield", FieldId: "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" { t.Error("Expecting: 2014-06-11 19:19:00, got: ", cdrVal) } // Test filter fltr, _ := utils.ParseRSRFields("~tenant:s/(.+)/itsyscom.com/", utils.INFIELD_SEP) cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: "cdrfield", FieldId: "stop_time", Value: val, FieldFilter: fltr, Layout: layout} if _, err := cdreTst.getDateTimeFieldVal(cdrTst, cfgCdrFld); err == nil { t.Error(err) } val, _ = utils.ParseRSRFields("fieldextr2", utils.INFIELD_SEP) cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: "cdrfield", FieldId: "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.") } }
func NewCfgCdrFieldFromCdrFieldJsonCfg(jsnCfgFld *CdrFieldJsonCfg) (*CfgCdrField, error) { var err error cfgFld := new(CfgCdrField) if jsnCfgFld.Tag != nil { cfgFld.Tag = *jsnCfgFld.Tag } if jsnCfgFld.Type != nil { cfgFld.Type = *jsnCfgFld.Type } if jsnCfgFld.Field_id != nil { cfgFld.FieldId = *jsnCfgFld.Field_id } if jsnCfgFld.Handler_id != nil { cfgFld.HandlerId = *jsnCfgFld.Handler_id } if jsnCfgFld.Value != nil { if cfgFld.Value, err = utils.ParseRSRFields(*jsnCfgFld.Value, utils.INFIELD_SEP); err != nil { return nil, err } } if jsnCfgFld.Append != nil { cfgFld.Append = *jsnCfgFld.Append } if jsnCfgFld.Field_filter != nil { if cfgFld.FieldFilter, err = utils.ParseRSRFields(*jsnCfgFld.Field_filter, utils.INFIELD_SEP); err != nil { return nil, err } } if jsnCfgFld.Width != nil { cfgFld.Width = *jsnCfgFld.Width } if jsnCfgFld.Strip != nil { cfgFld.Strip = *jsnCfgFld.Strip } if jsnCfgFld.Padding != nil { cfgFld.Padding = *jsnCfgFld.Padding } if jsnCfgFld.Layout != nil { cfgFld.Layout = *jsnCfgFld.Layout } if jsnCfgFld.Mandatory != nil { cfgFld.Mandatory = *jsnCfgFld.Mandatory } if jsnCfgFld.Cost_shift_digits != nil { cfgFld.CostShiftDigits = *jsnCfgFld.Cost_shift_digits } if jsnCfgFld.Rounding_decimals != nil { cfgFld.RoundingDecimals = *jsnCfgFld.Rounding_decimals } if jsnCfgFld.Timezone != nil { cfgFld.Timezone = *jsnCfgFld.Timezone } if jsnCfgFld.Mask_length != nil { cfgFld.MaskLen = *jsnCfgFld.Mask_length } if jsnCfgFld.Mask_destinationd_id != nil { cfgFld.MaskDestID = *jsnCfgFld.Mask_destinationd_id } return cfgFld, nil }
func (self *DARequestProcessor) loadFromJsonCfg(jsnCfg *DARequestProcessorJsnCfg) error { if jsnCfg == nil { return nil } if jsnCfg.Id != nil { self.Id = *jsnCfg.Id } if jsnCfg.Dry_run != nil { self.DryRun = *jsnCfg.Dry_run } if jsnCfg.Publish_event != nil { self.PublishEvent = *jsnCfg.Publish_event } var err error if jsnCfg.Request_filter != nil { if self.RequestFilter, err = utils.ParseRSRFields(*jsnCfg.Request_filter, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.CCR_fields != nil { if self.CCRFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.CCR_fields); err != nil { return err } } if jsnCfg.CCA_fields != nil { if self.CCAFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.CCA_fields); err != nil { return err } } return nil }
func (ps *PubSub) Subscribe(si SubscribeInfo, reply *string) error { ps.mux.Lock() defer ps.mux.Unlock() if si.Transport != utils.META_HTTP_POST { *reply = "Unsupported transport type" return errors.New(*reply) } var expTime time.Time if si.LifeSpan > 0 { expTime = time.Now().Add(si.LifeSpan) } rsr, err := utils.ParseRSRFields(si.EventFilter, utils.INFIELD_SEP) if err != nil { *reply = err.Error() return err } key := utils.InfieldJoin(si.Transport, si.Address) ps.subscribers[key] = &SubscriberData{ ExpTime: expTime, Filters: rsr, } ps.saveSubscriber(key) *reply = utils.OK return nil }
func TestCdreGetCombimedCdrFieldVal(t *testing.T) { cfg, _ := config.NewDefaultCGRConfig() cdrs := []*engine.CDR{ &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", 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, RunID: "RUN_RTL", Cost: 1.01}, &engine.CDR{CGRID: utils.Sha1("dsafdsaf2", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", 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, RunID: "CUSTOMER1", Cost: 2.01}, &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", 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, RunID: "CUSTOMER1", Cost: 3.01}, &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", 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, RunID: utils.DEFAULT_RUNID, Cost: 4.01}, &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", 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, RunID: "RETAIL1", Cost: 5.01}, } cdre, err := NewCdrExporter(cdrs, nil, cfg.CdreProfiles["*default"], cfg.CdreProfiles["*default"].CdrFormat, cfg.CdreProfiles["*default"].FieldSeparator, "firstexport", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 4, cfg.RoundingDecimals, "", 0, cfg.HttpSkipTlsVerify, "") if err != nil { t.Error("Unexpected error received: ", err) } fltrRule, _ := utils.ParseRSRFields("~RunID:s/default/RUN_RTL/", utils.INFIELD_SEP) val, _ := utils.ParseRSRFields(utils.COST, utils.INFIELD_SEP) cfgCdrFld := &config.CfgCdrField{Tag: "cost", Type: "cdrfield", FieldId: utils.COST, Value: val, FieldFilter: fltrRule} if costVal, err := cdre.getCombimedCdrFieldVal(cdrs[3], cfgCdrFld); err != nil { t.Error(err) } else if costVal != "1.01" { t.Error("Expecting: 1.01, received: ", costVal) } fltrRule, _ = utils.ParseRSRFields("~RunID:s/default/RETAIL1/", utils.INFIELD_SEP) val, _ = utils.ParseRSRFields(utils.ACCOUNT, utils.INFIELD_SEP) cfgCdrFld = &config.CfgCdrField{Tag: utils.ACCOUNT, Type: "cdrfield", FieldId: utils.ACCOUNT, Value: val, FieldFilter: fltrRule} if acntVal, err := cdre.getCombimedCdrFieldVal(cdrs[3], cfgCdrFld); err != nil { t.Error(err) } else if acntVal != "1000" { t.Error("Expecting: 1000, received: ", acntVal) } }
func NewCfgCdrFieldFromCdrFieldJsonCfg(jsnCfgFld *CdrFieldJsonCfg) (*CfgCdrField, error) { var err error cfgFld := new(CfgCdrField) if jsnCfgFld.Tag != nil { cfgFld.Tag = *jsnCfgFld.Tag } if jsnCfgFld.Type != nil { cfgFld.Type = *jsnCfgFld.Type } if jsnCfgFld.Field_id != nil { cfgFld.FieldId = *jsnCfgFld.Field_id } if jsnCfgFld.Handler_id != nil { cfgFld.HandlerId = *jsnCfgFld.Handler_id } if jsnCfgFld.Value != nil { if cfgFld.Value, err = utils.ParseRSRFields(*jsnCfgFld.Value, utils.INFIELD_SEP); err != nil { return nil, err } } if jsnCfgFld.Append != nil { cfgFld.Append = *jsnCfgFld.Append } if jsnCfgFld.Field_filter != nil { if cfgFld.FieldFilter, err = utils.ParseRSRFields(*jsnCfgFld.Field_filter, utils.INFIELD_SEP); err != nil { return nil, err } } if jsnCfgFld.Width != nil { cfgFld.Width = *jsnCfgFld.Width } if jsnCfgFld.Strip != nil { cfgFld.Strip = *jsnCfgFld.Strip } if jsnCfgFld.Padding != nil { cfgFld.Padding = *jsnCfgFld.Padding } if jsnCfgFld.Layout != nil { cfgFld.Layout = *jsnCfgFld.Layout } if jsnCfgFld.Mandatory != nil { cfgFld.Mandatory = *jsnCfgFld.Mandatory } return cfgFld, nil }
func (self *CdrServer) deriveCdrs(storedCdr *StoredCdr) ([]*StoredCdr, error) { if len(storedCdr.MediationRunId) == 0 { storedCdr.MediationRunId = utils.META_DEFAULT } cdrRuns := []*StoredCdr{storedCdr} if storedCdr.Rated { // Do not derive already rated CDRs since they should be already derived return cdrRuns, nil } attrsDC := &utils.AttrDerivedChargers{Tenant: storedCdr.Tenant, Category: storedCdr.Category, Direction: storedCdr.Direction, Account: storedCdr.Account, Subject: storedCdr.Subject, Destination: storedCdr.Destination} var dcs utils.DerivedChargers if err := self.rater.GetDerivedChargers(attrsDC, &dcs); err != nil { utils.Logger.Err(fmt.Sprintf("Could not get derived charging for cgrid %s, error: %s", storedCdr.CgrId, err.Error())) return nil, err } for _, dc := range dcs.Chargers { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if fltrPass, _ := storedCdr.PassesFieldFilter(dcRunFilter); !fltrPass { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } dcReqTypeFld, _ := utils.NewRSRField(dc.ReqTypeField) dcDirFld, _ := utils.NewRSRField(dc.DirectionField) dcTenantFld, _ := utils.NewRSRField(dc.TenantField) dcCategoryFld, _ := utils.NewRSRField(dc.CategoryField) dcAcntFld, _ := utils.NewRSRField(dc.AccountField) dcSubjFld, _ := utils.NewRSRField(dc.SubjectField) dcDstFld, _ := utils.NewRSRField(dc.DestinationField) dcSTimeFld, _ := utils.NewRSRField(dc.SetupTimeField) dcPddFld, _ := utils.NewRSRField(dc.PddField) dcATimeFld, _ := utils.NewRSRField(dc.AnswerTimeField) dcDurFld, _ := utils.NewRSRField(dc.UsageField) dcSupplFld, _ := utils.NewRSRField(dc.SupplierField) dcDCauseFld, _ := utils.NewRSRField(dc.DisconnectCauseField) dcRatedFld, _ := utils.NewRSRField(dc.RatedField) dcCostFld, _ := utils.NewRSRField(dc.CostField) forkedCdr, err := storedCdr.ForkCdr(dc.RunId, dcReqTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, dcSTimeFld, dcPddFld, dcATimeFld, dcDurFld, dcSupplFld, dcDCauseFld, dcRatedFld, dcCostFld, []*utils.RSRField{}, true, self.cgrCfg.DefaultTimezone) if err != nil { utils.Logger.Err(fmt.Sprintf("Could not fork CGR with cgrid %s, run: %s, error: %s", storedCdr.CgrId, dc.RunId, err.Error())) continue // do not add it to the forked CDR list } if !forkedCdr.Rated { forkedCdr.Cost = -1.0 // Make sure that un-rated CDRs start with Cost -1 } cdrRuns = append(cdrRuns, forkedCdr) } return cdrRuns, nil }
func TestCdreCdrFieldValue(t *testing.T) { cdre := new(CdrExporter) cdr := &engine.CDR{CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", 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, RunID: utils.DEFAULT_RUNID, Cost: 1.01} val, _ := utils.ParseRSRFields(utils.DESTINATION, utils.INFIELD_SEP) cfgCdrFld := &config.CfgCdrField{Tag: "destination", Type: "cdrfield", FieldId: utils.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.CfgCdrField{Tag: "destination", Type: "cdrfield", FieldId: utils.DESTINATION, Value: val, FieldFilter: fltr} if _, err := cdre.cdrFieldValue(cdr, cfgCdrFld); err == nil { t.Error("Failed to use filter") } }
func (csvr *CSVReader) LoadDerivedChargers() (err error) { csvReader, fp, err := csvr.readerFunc(csvr.derivedChargersFn, csvr.sep, utils.DERIVED_CHARGERS_NRCOLS) if err != nil { log.Print("Could not load derivedChargers file: ", err) // allow writing of the other values return nil } if fp != nil { defer fp.Close() } for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { if _, err = utils.ParseRSRFields(record[6], utils.INFIELD_SEP); err != nil { // Make sure rules are OK before loading in db return err } tag := utils.DerivedChargersKey(record[0], record[1], record[2], record[3], record[4]) if _, found := csvr.derivedChargers[tag]; found { if csvr.derivedChargers[tag], err = csvr.derivedChargers[tag].Append(&utils.DerivedCharger{ RunId: ValueOrDefault(record[5], "*default"), RunFilters: record[6], ReqTypeField: ValueOrDefault(record[7], "*default"), DirectionField: ValueOrDefault(record[8], "*default"), TenantField: ValueOrDefault(record[9], "*default"), CategoryField: ValueOrDefault(record[10], "*default"), AccountField: ValueOrDefault(record[11], "*default"), SubjectField: ValueOrDefault(record[12], "*default"), DestinationField: ValueOrDefault(record[13], "*default"), SetupTimeField: ValueOrDefault(record[14], "*default"), AnswerTimeField: ValueOrDefault(record[15], "*default"), UsageField: ValueOrDefault(record[16], "*default"), }); err != nil { return err } } else { if record[5] == utils.DEFAULT_RUNID { return errors.New("Reserved RunId") } csvr.derivedChargers[tag] = utils.DerivedChargers{&utils.DerivedCharger{ RunId: ValueOrDefault(record[5], "*default"), RunFilters: record[6], ReqTypeField: ValueOrDefault(record[7], "*default"), DirectionField: ValueOrDefault(record[8], "*default"), TenantField: ValueOrDefault(record[9], "*default"), CategoryField: ValueOrDefault(record[10], "*default"), AccountField: ValueOrDefault(record[11], "*default"), SubjectField: ValueOrDefault(record[12], "*default"), DestinationField: ValueOrDefault(record[13], "*default"), SetupTimeField: ValueOrDefault(record[14], "*default"), AnswerTimeField: ValueOrDefault(record[15], "*default"), UsageField: ValueOrDefault(record[16], "*default"), }} } } return }
func TestCDRAsExportRecord(t *testing.T) { cdr := &CDR{CGRID: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), ToR: utils.VOICE, OriginID: "dsafdsaf", OriginHost: "192.168.1.1", RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org", 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, RunID: utils.DEFAULT_RUNID, Cost: 1.01, ExtraFields: map[string]string{"stop_time": "2014-06-11 19:19:00 +0000 UTC", "fieldextr2": "valextr2"}} val, _ := utils.ParseRSRFields(utils.DESTINATION, utils.INFIELD_SEP) cfgCdrFld := &config.CfgCdrField{Tag: "destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, Value: val} if expRecord, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err != nil { t.Error(err) } else if expRecord[0] != cdr.Destination { t.Errorf("Expecting: %s, received: %s", cdr.Destination, expRecord[0]) } fltr, _ := utils.ParseRSRFields("Tenant(itsyscom.com)", utils.INFIELD_SEP) cfgCdrFld = &config.CfgCdrField{Tag: "destination", Type: utils.META_COMPOSED, FieldId: utils.DESTINATION, Value: val, FieldFilter: fltr} if _, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err == nil { t.Error("Failed to use filter") } // Test MetaDateTime val, _ = utils.ParseRSRFields("stop_time", utils.INFIELD_SEP) layout := "2006-01-02 15:04:05" cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: utils.MetaDateTime, FieldId: "stop_time", Value: val, Layout: layout} if expRecord, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err != nil { t.Error(err) } else if expRecord[0] != "2014-06-11 19:19:00" { t.Error("Expecting: 2014-06-11 19:19:00, got: ", expRecord[0]) } // Test filter fltr, _ = utils.ParseRSRFields("Tenant(itsyscom.com)", utils.INFIELD_SEP) cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: utils.MetaDateTime, FieldId: "stop_time", Value: val, FieldFilter: fltr, Layout: layout} if _, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err == nil { t.Error("Received empty error", err) } val, _ = utils.ParseRSRFields("fieldextr2", utils.INFIELD_SEP) cfgCdrFld = &config.CfgCdrField{Tag: "stop_time", Type: utils.MetaDateTime, FieldId: "stop_time", Value: val, Layout: layout} // Test time parse error if _, err := cdr.AsExportRecord([]*config.CfgCdrField{cfgCdrFld}, 0, 0, "UTC", false, 0, "", nil); err == nil { t.Error("Should give error here, got none.") } }
func (self *ApierV1) SetDerivedChargers(attrs AttrSetDerivedChargers, reply *string) (err error) { if len(attrs.DerivedChargers) == 0 { return utils.NewErrMandatoryIeMissing("DerivedChargers") } if len(attrs.Direction) == 0 { attrs.Direction = utils.OUT } if len(attrs.Tenant) == 0 { attrs.Tenant = utils.ANY } if len(attrs.Category) == 0 { attrs.Category = utils.ANY } if len(attrs.Account) == 0 { attrs.Account = utils.ANY } if len(attrs.Subject) == 0 { attrs.Subject = utils.ANY } for _, dc := range attrs.DerivedChargers { if _, err = utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP); err != nil { // Make sure rules are OK before loading in db return fmt.Errorf("%s:%s", utils.ErrParserError.Error(), err.Error()) } } dcKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, attrs.Category, attrs.Account, attrs.Subject) if !attrs.Overwrite { if exists, err := self.RatingDb.HasData(utils.DERIVEDCHARGERS_PREFIX, dcKey); err != nil { return utils.NewErrServerError(err) } else if exists { return utils.ErrExists } } dstIds := strings.Split(attrs.DestinationIds, utils.INFIELD_SEP) dcs := &utils.DerivedChargers{DestinationIDs: utils.NewStringMap(dstIds...), Chargers: attrs.DerivedChargers} if err := self.RatingDb.SetDerivedChargers(dcKey, dcs); err != nil { return utils.NewErrServerError(err) } if err := self.RatingDb.CacheRatingPrefixValues(map[string][]string{ utils.DERIVEDCHARGERS_PREFIX: []string{utils.DERIVEDCHARGERS_PREFIX + dcKey}, }); err != nil { return utils.NewErrServerError(err) } *reply = utils.OK return nil }
func (self *ApierV1) SetDerivedChargers(attrs AttrSetDerivedChargers, reply *string) (err error) { if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Category", "Direction", "Account", "Subject", "DerivedChargers"}); len(missing) != 0 { return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) } for _, dc := range attrs.DerivedChargers { if _, err = utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP); err != nil { // Make sure rules are OK before loading in db return fmt.Errorf("%s:%s", utils.ERR_PARSER_ERROR, err.Error()) } } dcKey := utils.DerivedChargersKey(attrs.Direction, attrs.Tenant, attrs.Category, attrs.Account, attrs.Subject) if err := self.AccountDb.SetDerivedChargers(dcKey, attrs.DerivedChargers); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } if err := self.AccountDb.CacheAccounting([]string{}, []string{}, []string{}, []string{engine.DERIVEDCHARGERS_PREFIX + dcKey}); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } *reply = utils.OK return nil }
func (self *DARequestProcessor) loadFromJsonCfg(jsnCfg *DARequestProcessorJsnCfg) error { if jsnCfg == nil { return nil } if jsnCfg.Id != nil { self.Id = *jsnCfg.Id } if jsnCfg.Dry_run != nil { self.DryRun = *jsnCfg.Dry_run } if jsnCfg.Publish_event != nil { self.PublishEvent = *jsnCfg.Publish_event } var err error if jsnCfg.Request_filter != nil { if self.RequestFilter, err = utils.ParseRSRFields(*jsnCfg.Request_filter, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Flags != nil { self.Flags = utils.StringMapFromSlice(*jsnCfg.Flags) } if jsnCfg.Continue_on_success != nil { self.ContinueOnSuccess = *jsnCfg.Continue_on_success } if jsnCfg.Append_cca != nil { self.AppendCCA = *jsnCfg.Append_cca } if jsnCfg.CCR_fields != nil { if self.CCRFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.CCR_fields); err != nil { return err } } if jsnCfg.CCA_fields != nil { if self.CCAFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.CCA_fields); err != nil { return err } } return nil }
func (cdrcFld *CdrcField) PopulateRSRFields() (err error) { if cdrcFld.rsrFields, err = utils.ParseRSRFields(cdrcFld.Value, utils.INFIELD_SEP); err != nil { return err } return nil }
// 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 err } jsnListenCfg, err := jsnCfg.ListenJsonCfg() if err != nil { return err } jsnTpDbCfg, err := jsnCfg.DbJsonCfg(TPDB_JSN) if err != nil { return err } jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN) if err != nil { return err } jsnStorDbCfg, err := jsnCfg.DbJsonCfg(STORDB_JSN) if err != nil { return err } jsnBalancerCfg, err := jsnCfg.BalancerJsonCfg() if err != nil { return err } jsnRaterCfg, err := jsnCfg.RaterJsonCfg() if err != nil { return err } jsnSchedCfg, err := jsnCfg.SchedulerJsonCfg() if err != nil { return err } jsnCdrsCfg, err := jsnCfg.CdrsJsonCfg() if err != nil { return err } jsnCdrstatsCfg, err := jsnCfg.CdrStatsJsonCfg() if err != nil { return err } jsnCdreCfg, err := jsnCfg.CdreJsonCfgs() if err != nil { return err } jsnCdrcCfg, err := jsnCfg.CdrcJsonCfg() if err != nil { return err } jsnSmFsCfg, err := jsnCfg.SmFsJsonCfg() if err != nil { return err } jsnSmKamCfg, err := jsnCfg.SmKamJsonCfg() if err != nil { return err } jsnSmOsipsCfg, err := jsnCfg.SmOsipsJsonCfg() if err != nil { return err } jsnHistServCfg, err := jsnCfg.HistServJsonCfg() if err != nil { return err } jsnPubSubServCfg, err := jsnCfg.PubSubServJsonCfg() if err != nil { return err } jsnAliasesServCfg, err := jsnCfg.AliasesServJsonCfg() if err != nil { return err } jsnUserServCfg, err := jsnCfg.UserServJsonCfg() if err != nil { return err } jsnMailerCfg, err := jsnCfg.MailerJsonCfg() if err != nil { return err } // All good, start populating config variables if jsnTpDbCfg != nil { if jsnTpDbCfg.Db_type != nil { self.TpDbType = *jsnTpDbCfg.Db_type } if jsnTpDbCfg.Db_host != nil { self.TpDbHost = *jsnTpDbCfg.Db_host } if jsnTpDbCfg.Db_port != nil { self.TpDbPort = strconv.Itoa(*jsnTpDbCfg.Db_port) } if jsnTpDbCfg.Db_name != nil { self.TpDbName = *jsnTpDbCfg.Db_name } if jsnTpDbCfg.Db_user != nil { self.TpDbUser = *jsnTpDbCfg.Db_user } if jsnTpDbCfg.Db_passwd != nil { self.TpDbPass = *jsnTpDbCfg.Db_passwd } } if jsnDataDbCfg != nil { if jsnDataDbCfg.Db_type != nil { self.DataDbType = *jsnDataDbCfg.Db_type } if jsnDataDbCfg.Db_host != nil { self.DataDbHost = *jsnDataDbCfg.Db_host } if jsnDataDbCfg.Db_port != nil { self.DataDbPort = strconv.Itoa(*jsnDataDbCfg.Db_port) } if jsnDataDbCfg.Db_name != nil { self.DataDbName = *jsnDataDbCfg.Db_name } if jsnDataDbCfg.Db_user != nil { self.DataDbUser = *jsnDataDbCfg.Db_user } if jsnDataDbCfg.Db_passwd != nil { self.DataDbPass = *jsnDataDbCfg.Db_passwd } if jsnDataDbCfg.Load_history_size != nil { self.LoadHistorySize = *jsnDataDbCfg.Load_history_size } } 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 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.Connect_attempts != nil { self.ConnectAttempts = *jsnGeneralCfg.Connect_attempts } if jsnGeneralCfg.Response_cache_ttl != nil { if self.ResponseCacheTTL, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Response_cache_ttl); err != nil { return err } } if jsnGeneralCfg.Reconnects != nil { self.Reconnects = *jsnGeneralCfg.Reconnects } if jsnGeneralCfg.Rounding_decimals != nil { self.RoundingDecimals = *jsnGeneralCfg.Rounding_decimals } if jsnGeneralCfg.Http_skip_tls_verify != nil { self.HttpSkipTlsVerify = *jsnGeneralCfg.Http_skip_tls_verify } if jsnGeneralCfg.Tpexport_dir != nil { self.TpExportPath = *jsnGeneralCfg.Tpexport_dir } if jsnGeneralCfg.Default_timezone != nil { self.DefaultTimezone = *jsnGeneralCfg.Default_timezone } if jsnGeneralCfg.Internal_ttl != nil { if self.InternalTtl, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Internal_ttl); err != nil { return err } } } 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 jsnRaterCfg != nil { if jsnRaterCfg.Enabled != nil { self.RaterEnabled = *jsnRaterCfg.Enabled } if jsnRaterCfg.Balancer != nil { self.RaterBalancer = *jsnRaterCfg.Balancer } if jsnRaterCfg.Cdrstats != nil { self.RaterCdrStats = *jsnRaterCfg.Cdrstats } if jsnRaterCfg.Historys != nil { self.RaterHistoryServer = *jsnRaterCfg.Historys } if jsnRaterCfg.Pubsubs != nil { self.RaterPubSubServer = *jsnRaterCfg.Pubsubs } if jsnRaterCfg.Aliases != nil { self.RaterAliasesServer = *jsnRaterCfg.Aliases } if jsnRaterCfg.Users != nil { self.RaterUserServer = *jsnRaterCfg.Users } } if jsnBalancerCfg != nil && jsnBalancerCfg.Enabled != nil { self.BalancerEnabled = *jsnBalancerCfg.Enabled } if jsnSchedCfg != nil && jsnSchedCfg.Enabled != nil { self.SchedulerEnabled = *jsnSchedCfg.Enabled } 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.Store_cdrs != nil { self.CDRSStoreCdrs = *jsnCdrsCfg.Store_cdrs } if jsnCdrsCfg.Rater != nil { self.CDRSRater = *jsnCdrsCfg.Rater } if jsnCdrsCfg.Pubsubs != nil { self.CDRSPubSub = *jsnCdrsCfg.Pubsubs } if jsnCdrsCfg.Users != nil { self.CDRSUsers = *jsnCdrsCfg.Users } if jsnCdrsCfg.Aliases != nil { self.CDRSAliases = *jsnCdrsCfg.Aliases } if jsnCdrsCfg.Cdrstats != nil { self.CDRSStats = *jsnCdrsCfg.Cdrstats } if jsnCdrsCfg.Cdr_replication != nil { self.CDRSCdrReplication = make([]*CdrReplicationCfg, len(*jsnCdrsCfg.Cdr_replication)) for idx, rplJsonCfg := range *jsnCdrsCfg.Cdr_replication { self.CDRSCdrReplication[idx] = new(CdrReplicationCfg) if rplJsonCfg.Transport != nil { self.CDRSCdrReplication[idx].Transport = *rplJsonCfg.Transport } if rplJsonCfg.Server != nil { self.CDRSCdrReplication[idx].Server = *rplJsonCfg.Server } if rplJsonCfg.Synchronous != nil { self.CDRSCdrReplication[idx].Synchronous = *rplJsonCfg.Synchronous } if rplJsonCfg.Cdr_filter != nil { if self.CDRSCdrReplication[idx].CdrFilter, err = utils.ParseRSRFields(*rplJsonCfg.Cdr_filter, utils.INFIELD_SEP); err != nil { return err } } } } } if jsnCdrstatsCfg != nil { if jsnCdrstatsCfg.Enabled != nil { self.CDRStatsEnabled = *jsnCdrstatsCfg.Enabled if jsnCdrstatsCfg.Save_Interval != nil { if self.CDRStatsSaveInterval, err = utils.ParseDurationWithSecs(*jsnCdrstatsCfg.Save_Interval); err != nil { return 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.dfltCdreProfile.Clone() // Clone default so we do not inherit pointers } } if err = self.CdreProfiles[profileName].loadFromJsonCfg(jsnCdre1Cfg); err != nil { // Update the existing profile with content from json config return err } } } if jsnCdrcCfg != nil { if self.CdrcProfiles == nil { self.CdrcProfiles = make(map[string]map[string]*CdrcConfig) } for profileName, jsnCrc1Cfg := range jsnCdrcCfg { if _, hasDir := self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir]; !hasDir { self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir] = make(map[string]*CdrcConfig) } if _, hasProfile := self.CdrcProfiles[profileName]; !hasProfile { if profileName == utils.META_DEFAULT { self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir][profileName] = new(CdrcConfig) } else { self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir][profileName] = self.dfltCdrcProfile.Clone() // Clone default so we do not inherit pointers } } if err = self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir][profileName].loadFromJsonCfg(jsnCrc1Cfg); err != nil { return err } } } if jsnSmFsCfg != nil { if err := self.SmFsConfig.loadFromJsonCfg(jsnSmFsCfg); err != nil { return err } } if jsnSmKamCfg != nil { if err := self.SmKamConfig.loadFromJsonCfg(jsnSmKamCfg); err != nil { return err } } if jsnSmOsipsCfg != nil { if err := self.SmOsipsConfig.loadFromJsonCfg(jsnSmOsipsCfg); err != nil { return err } } 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 jsnPubSubServCfg != nil { if jsnPubSubServCfg.Enabled != nil { self.PubSubServerEnabled = *jsnPubSubServCfg.Enabled } } if jsnAliasesServCfg != nil { if jsnAliasesServCfg.Enabled != nil { self.AliasesServerEnabled = *jsnAliasesServCfg.Enabled } } if jsnUserServCfg != nil { if jsnUserServCfg.Enabled != nil { self.UserServerEnabled = *jsnUserServCfg.Enabled } if jsnUserServCfg.Indexes != nil { self.UserServerIndexes = *jsnUserServCfg.Indexes } } 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 } } return nil }
func (sm *FSSessionManager) OnChannelPark(ev Event) { var maxCallDuration time.Duration // This will be the maximum duration this channel will be allowed to last var durInitialized bool attrsDC := utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT), Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)} var dcs utils.DerivedChargers if err := sm.rater.GetDerivedChargers(attrsDC, &dcs); err != nil { engine.Logger.Err(fmt.Sprintf("<SessionManager> OnPark: could not get derived charging for event %s: %s", ev.GetUUID(), err.Error())) sm.unparkCall(ev.GetUUID(), ev.GetCallDestNr(utils.META_DEFAULT), SYSTEM_ERROR) // We unpark on original destination return } dcs, _ = dcs.AppendDefaultRun() for _, dc := range dcs { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if fltrPass, _ := ev.PassesFieldFilter(dcRunFilter); !fltrPass { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } startTime, err := ev.GetAnswerTime(PARK_TIME) if err != nil { engine.Logger.Err("Error parsing answer event start time, using time.Now!") startTime = time.Now() } if ev.MissingParameter() { sm.unparkCall(ev.GetUUID(), ev.GetCallDestNr(dc.DestinationField), MISSING_PARAMETER) engine.Logger.Err(fmt.Sprintf("Missing parameter for %s", ev.GetUUID())) return } cd := engine.CallDescriptor{ Direction: ev.GetDirection(dc.DirectionField), Tenant: ev.GetTenant(dc.TenantField), Category: ev.GetCategory(dc.CategoryField), Subject: ev.GetSubject(dc.SubjectField), Account: ev.GetAccount(dc.AccountField), Destination: ev.GetDestination(dc.DestinationField), TimeStart: startTime, TimeEnd: startTime.Add(cfg.SMMaxCallDuration), } var remainingDurationFloat float64 err = sm.rater.GetMaxSessionTime(cd, &remainingDurationFloat) if err != nil { engine.Logger.Err(fmt.Sprintf("Could not get max session time for %s: %v", ev.GetUUID(), err)) sm.unparkCall(ev.GetUUID(), ev.GetCallDestNr(""), SYSTEM_ERROR) // We unpark on original destination return } remainingDuration := time.Duration(remainingDurationFloat) // Set maxCallDuration, smallest out of all forked sessions if !durInitialized { // first time we set it /not initialized yet maxCallDuration = remainingDuration durInitialized = true } else if maxCallDuration > remainingDuration { maxCallDuration = remainingDuration } } if maxCallDuration <= cfg.SMMinCallDuration { //engine.Logger.Info(fmt.Sprintf("Not enough credit for trasferring the call %s for %s.", ev.GetUUID(), cd.GetKey(cd.Subject))) sm.unparkCall(ev.GetUUID(), ev.GetCallDestNr(utils.META_DEFAULT), INSUFFICIENT_FUNDS) return } sm.setMaxCallDuration(ev.GetUUID(), maxCallDuration) sm.unparkCall(ev.GetUUID(), ev.GetCallDestNr(utils.META_DEFAULT), AUTH_OK) }
func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error { if jsnCfg == nil { return nil } var err error if jsnCfg.Id != nil { self.ID = *jsnCfg.Id } if jsnCfg.Enabled != nil { self.Enabled = *jsnCfg.Enabled } if jsnCfg.Dry_run != nil { self.DryRun = *jsnCfg.Dry_run } if jsnCfg.Cdrs_conns != nil { self.CdrsConns = make([]*HaPoolConfig, len(*jsnCfg.Cdrs_conns)) for idx, jsnHaCfg := range *jsnCfg.Cdrs_conns { self.CdrsConns[idx] = NewDfltHaPoolConfig() self.CdrsConns[idx].loadFromJsonCfg(jsnHaCfg) } } 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.Timezone != nil { self.Timezone = *jsnCfg.Timezone } if jsnCfg.Run_delay != nil { self.RunDelay = time.Duration(*jsnCfg.Run_delay) * time.Second } if jsnCfg.Max_open_files != nil { self.MaxOpenFiles = *jsnCfg.Max_open_files } 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.Failed_calls_prefix != nil { self.FailedCallsPrefix = *jsnCfg.Failed_calls_prefix } if jsnCfg.Cdr_path != nil { self.CDRPath = utils.ParseHierarchyPath(*jsnCfg.Cdr_path, "") } if jsnCfg.Cdr_source_id != nil { self.CdrSourceId = *jsnCfg.Cdr_source_id } if jsnCfg.Cdr_filter != nil { if self.CdrFilter, err = utils.ParseRSRFields(*jsnCfg.Cdr_filter, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Continue_on_success != nil { self.ContinueOnSuccess = *jsnCfg.Continue_on_success } if jsnCfg.Partial_record_cache != nil { if self.PartialRecordCache, err = utils.ParseDurationWithSecs(*jsnCfg.Partial_record_cache); err != nil { return err } } if jsnCfg.Partial_cache_expiry_action != nil { self.PartialCacheExpiryAction = *jsnCfg.Partial_cache_expiry_action } 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 } } if jsnCfg.Cache_dump_fields != nil { if self.CacheDumpFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Cache_dump_fields); err != nil { return err } } return nil }
// 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 err } // Load sections out of JSON config, stop on error jsnCacheCfg, err := jsnCfg.CacheJsonCfg() if err != nil { return err } jsnListenCfg, err := jsnCfg.ListenJsonCfg() if err != nil { return err } jsnTpDbCfg, err := jsnCfg.DbJsonCfg(TPDB_JSN) if err != nil { return err } jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN) if err != nil { return err } jsnStorDbCfg, err := jsnCfg.DbJsonCfg(STORDB_JSN) if err != nil { return err } jsnBalancerCfg, err := jsnCfg.BalancerJsonCfg() if err != nil { return err } jsnRALsCfg, err := jsnCfg.RalsJsonCfg() if err != nil { return err } jsnSchedCfg, err := jsnCfg.SchedulerJsonCfg() if err != nil { return err } jsnCdrsCfg, err := jsnCfg.CdrsJsonCfg() if err != nil { return err } jsnCdrstatsCfg, err := jsnCfg.CdrStatsJsonCfg() if err != nil { return err } jsnCdreCfg, err := jsnCfg.CdreJsonCfgs() if err != nil { return err } jsnCdrcCfg, err := jsnCfg.CdrcJsonCfg() if err != nil { return err } jsnSmGenericCfg, err := jsnCfg.SmGenericJsonCfg() if err != nil { return err } jsnSmFsCfg, err := jsnCfg.SmFsJsonCfg() if err != nil { return err } jsnSmKamCfg, err := jsnCfg.SmKamJsonCfg() if err != nil { return err } jsnSmOsipsCfg, err := jsnCfg.SmOsipsJsonCfg() if err != nil { return err } jsnSMAstCfg, err := jsnCfg.SmAsteriskJsonCfg() if err != nil { return err } jsnDACfg, err := jsnCfg.DiameterAgentJsonCfg() if err != nil { return err } jsnHistServCfg, err := jsnCfg.HistServJsonCfg() if err != nil { return err } jsnPubSubServCfg, err := jsnCfg.PubSubServJsonCfg() if err != nil { return err } jsnAliasesServCfg, err := jsnCfg.AliasesServJsonCfg() if err != nil { return err } jsnUserServCfg, err := jsnCfg.UserServJsonCfg() if err != nil { return err } jsnRLSCfg, err := jsnCfg.ResourceLimiterJsonCfg() if err != nil { return err } jsnMailerCfg, err := jsnCfg.MailerJsonCfg() if err != nil { return err } jsnSureTaxCfg, err := jsnCfg.SureTaxJsonCfg() if err != nil { return err } // All good, start populating config variables if jsnTpDbCfg != nil { if jsnTpDbCfg.Db_type != nil { self.TpDbType = *jsnTpDbCfg.Db_type } if jsnTpDbCfg.Db_host != nil { self.TpDbHost = *jsnTpDbCfg.Db_host } if jsnTpDbCfg.Db_port != nil { self.TpDbPort = strconv.Itoa(*jsnTpDbCfg.Db_port) } if jsnTpDbCfg.Db_name != nil { self.TpDbName = *jsnTpDbCfg.Db_name } if jsnTpDbCfg.Db_user != nil { self.TpDbUser = *jsnTpDbCfg.Db_user } if jsnTpDbCfg.Db_password != nil { self.TpDbPass = *jsnTpDbCfg.Db_password } } if jsnDataDbCfg != nil { if jsnDataDbCfg.Db_type != nil { self.DataDbType = *jsnDataDbCfg.Db_type } if jsnDataDbCfg.Db_host != nil { self.DataDbHost = *jsnDataDbCfg.Db_host } if jsnDataDbCfg.Db_port != nil { self.DataDbPort = strconv.Itoa(*jsnDataDbCfg.Db_port) } if jsnDataDbCfg.Db_name != nil { self.DataDbName = *jsnDataDbCfg.Db_name } if jsnDataDbCfg.Db_user != nil { self.DataDbUser = *jsnDataDbCfg.Db_user } if jsnDataDbCfg.Db_password != nil { self.DataDbPass = *jsnDataDbCfg.Db_password } if jsnDataDbCfg.Load_history_size != nil { self.LoadHistorySize = *jsnDataDbCfg.Load_history_size } } 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_password != nil { self.StorDBPass = *jsnStorDbCfg.Db_password } 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 jsnStorDbCfg.Cdrs_indexes != nil { self.StorDBCDRSIndexes = *jsnStorDbCfg.Cdrs_indexes } } if jsnGeneralCfg != nil { if jsnGeneralCfg.Dbdata_encoding != nil { self.DBDataEncoding = *jsnGeneralCfg.Dbdata_encoding } if jsnGeneralCfg.Default_request_type != nil { self.DefaultReqType = *jsnGeneralCfg.Default_request_type } if jsnGeneralCfg.Default_category != nil { self.DefaultCategory = *jsnGeneralCfg.Default_category } if jsnGeneralCfg.Default_tenant != nil { self.DefaultTenant = *jsnGeneralCfg.Default_tenant } if jsnGeneralCfg.Connect_attempts != nil { self.ConnectAttempts = *jsnGeneralCfg.Connect_attempts } if jsnGeneralCfg.Response_cache_ttl != nil { if self.ResponseCacheTTL, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Response_cache_ttl); err != nil { return err } } if jsnGeneralCfg.Reconnects != nil { self.Reconnects = *jsnGeneralCfg.Reconnects } if jsnGeneralCfg.Connect_timeout != nil { if self.ConnectTimeout, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Connect_timeout); err != nil { return err } } if jsnGeneralCfg.Reply_timeout != nil { if self.ReplyTimeout, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Reply_timeout); err != nil { return err } } if jsnGeneralCfg.Rounding_decimals != nil { self.RoundingDecimals = *jsnGeneralCfg.Rounding_decimals } if jsnGeneralCfg.Http_skip_tls_verify != nil { self.HttpSkipTlsVerify = *jsnGeneralCfg.Http_skip_tls_verify } if jsnGeneralCfg.Tpexport_dir != nil { self.TpExportPath = *jsnGeneralCfg.Tpexport_dir } if jsnGeneralCfg.Httpposter_attempts != nil { self.HttpPosterAttempts = *jsnGeneralCfg.Httpposter_attempts } if jsnGeneralCfg.Http_failed_dir != nil { self.HttpFailedDir = *jsnGeneralCfg.Http_failed_dir } if jsnGeneralCfg.Default_timezone != nil { self.DefaultTimezone = *jsnGeneralCfg.Default_timezone } if jsnGeneralCfg.Internal_ttl != nil { if self.InternalTtl, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Internal_ttl); err != nil { return err } } if jsnGeneralCfg.Locking_timeout != nil { if self.LockingTimeout, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Locking_timeout); err != nil { return err } } } if jsnCacheCfg != nil { if err := self.CacheConfig.loadFromJsonCfg(jsnCacheCfg); err != nil { return err } } 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 jsnRALsCfg != nil { if jsnRALsCfg.Enabled != nil { self.RALsEnabled = *jsnRALsCfg.Enabled } if jsnRALsCfg.Balancer != nil { self.RALsBalancer = *jsnRALsCfg.Balancer } if jsnRALsCfg.Cdrstats_conns != nil { self.RALsCDRStatSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Cdrstats_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Cdrstats_conns { self.RALsCDRStatSConns[idx] = NewDfltHaPoolConfig() self.RALsCDRStatSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Historys_conns != nil { self.RALsHistorySConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Historys_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Historys_conns { self.RALsHistorySConns[idx] = NewDfltHaPoolConfig() self.RALsHistorySConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Pubsubs_conns != nil { self.RALsPubSubSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Pubsubs_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Pubsubs_conns { self.RALsPubSubSConns[idx] = NewDfltHaPoolConfig() self.RALsPubSubSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Aliases_conns != nil { self.RALsAliasSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Aliases_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Aliases_conns { self.RALsAliasSConns[idx] = NewDfltHaPoolConfig() self.RALsAliasSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Users_conns != nil { self.RALsUserSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Users_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Users_conns { self.RALsUserSConns[idx] = NewDfltHaPoolConfig() self.RALsUserSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Rp_subject_prefix_matching != nil { self.RpSubjectPrefixMatching = *jsnRALsCfg.Rp_subject_prefix_matching } if jsnRALsCfg.Lcr_subject_prefix_matching != nil { self.LcrSubjectPrefixMatching = *jsnRALsCfg.Lcr_subject_prefix_matching } } if jsnBalancerCfg != nil && jsnBalancerCfg.Enabled != nil { self.BalancerEnabled = *jsnBalancerCfg.Enabled } if jsnSchedCfg != nil && jsnSchedCfg.Enabled != nil { self.SchedulerEnabled = *jsnSchedCfg.Enabled } 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.Store_cdrs != nil { self.CDRSStoreCdrs = *jsnCdrsCfg.Store_cdrs } if jsnCdrsCfg.Cdr_account_summary != nil { self.CDRScdrAccountSummary = *jsnCdrsCfg.Cdr_account_summary } if jsnCdrsCfg.Rals_conns != nil { self.CDRSRaterConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Rals_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Rals_conns { self.CDRSRaterConns[idx] = NewDfltHaPoolConfig() self.CDRSRaterConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Pubsubs_conns != nil { self.CDRSPubSubSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Pubsubs_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Pubsubs_conns { self.CDRSPubSubSConns[idx] = NewDfltHaPoolConfig() self.CDRSPubSubSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Users_conns != nil { self.CDRSUserSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Users_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Users_conns { self.CDRSUserSConns[idx] = NewDfltHaPoolConfig() self.CDRSUserSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Aliases_conns != nil { self.CDRSAliaseSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Aliases_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Aliases_conns { self.CDRSAliaseSConns[idx] = NewDfltHaPoolConfig() self.CDRSAliaseSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Cdrstats_conns != nil { self.CDRSStatSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Cdrstats_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Cdrstats_conns { self.CDRSStatSConns[idx] = NewDfltHaPoolConfig() self.CDRSStatSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Cdr_replication != nil { self.CDRSCdrReplication = make([]*CdrReplicationCfg, len(*jsnCdrsCfg.Cdr_replication)) for idx, rplJsonCfg := range *jsnCdrsCfg.Cdr_replication { self.CDRSCdrReplication[idx] = new(CdrReplicationCfg) if rplJsonCfg.Transport != nil { self.CDRSCdrReplication[idx].Transport = *rplJsonCfg.Transport } if rplJsonCfg.Address != nil { self.CDRSCdrReplication[idx].Address = *rplJsonCfg.Address } if rplJsonCfg.Synchronous != nil { self.CDRSCdrReplication[idx].Synchronous = *rplJsonCfg.Synchronous } self.CDRSCdrReplication[idx].Attempts = 1 if rplJsonCfg.Attempts != nil { self.CDRSCdrReplication[idx].Attempts = *rplJsonCfg.Attempts } if rplJsonCfg.Cdr_filter != nil { if self.CDRSCdrReplication[idx].CdrFilter, err = utils.ParseRSRFields(*rplJsonCfg.Cdr_filter, utils.INFIELD_SEP); err != nil { return err } } } } } if jsnCdrstatsCfg != nil { if jsnCdrstatsCfg.Enabled != nil { self.CDRStatsEnabled = *jsnCdrstatsCfg.Enabled if jsnCdrstatsCfg.Save_Interval != nil { if self.CDRStatsSaveInterval, err = utils.ParseDurationWithSecs(*jsnCdrstatsCfg.Save_Interval); err != nil { return 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.dfltCdreProfile.Clone() // Clone default so we do not inherit pointers } } if err = self.CdreProfiles[profileName].loadFromJsonCfg(jsnCdre1Cfg); err != nil { // Update the existing profile with content from json config return err } } } if jsnCdrcCfg != nil { if self.CdrcProfiles == nil { self.CdrcProfiles = make(map[string][]*CdrcConfig) } for _, jsnCrc1Cfg := range jsnCdrcCfg { if jsnCrc1Cfg.Id == nil || *jsnCrc1Cfg.Id == "" { return errors.New("CDRC profile without an id") } if *jsnCrc1Cfg.Id == utils.META_DEFAULT { if self.dfltCdrcProfile == nil { self.dfltCdrcProfile = new(CdrcConfig) } } indxFound := -1 // Will be different than -1 if an instance with same id will be found pathFound := "" // Will be populated with the path where slice of cfgs was found var cdrcInstCfg *CdrcConfig for path := range self.CdrcProfiles { for i := range self.CdrcProfiles[path] { if self.CdrcProfiles[path][i].ID == *jsnCrc1Cfg.Id { indxFound = i pathFound = path cdrcInstCfg = self.CdrcProfiles[path][i] break } } } if cdrcInstCfg == nil { cdrcInstCfg = self.dfltCdrcProfile.Clone() } if err := cdrcInstCfg.loadFromJsonCfg(jsnCrc1Cfg); err != nil { return err } if cdrcInstCfg.CdrInDir == "" { return errors.New("CDRC profile without cdr_in_dir") } if _, hasDir := self.CdrcProfiles[cdrcInstCfg.CdrInDir]; !hasDir { self.CdrcProfiles[cdrcInstCfg.CdrInDir] = make([]*CdrcConfig, 0) } if indxFound != -1 { // Replace previous config so we have inheritance self.CdrcProfiles[pathFound][indxFound] = cdrcInstCfg } else { self.CdrcProfiles[cdrcInstCfg.CdrInDir] = append(self.CdrcProfiles[cdrcInstCfg.CdrInDir], cdrcInstCfg) } } } if jsnSmGenericCfg != nil { if err := self.SmGenericConfig.loadFromJsonCfg(jsnSmGenericCfg); err != nil { return err } } if jsnSmFsCfg != nil { if err := self.SmFsConfig.loadFromJsonCfg(jsnSmFsCfg); err != nil { return err } } if jsnSmKamCfg != nil { if err := self.SmKamConfig.loadFromJsonCfg(jsnSmKamCfg); err != nil { return err } } if jsnSmOsipsCfg != nil { if err := self.SmOsipsConfig.loadFromJsonCfg(jsnSmOsipsCfg); err != nil { return err } } if jsnSMAstCfg != nil { if err := self.smAsteriskCfg.loadFromJsonCfg(jsnSMAstCfg); err != nil { return err } } if jsnDACfg != nil { if err := self.diameterAgentCfg.loadFromJsonCfg(jsnDACfg); err != nil { return err } } 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 jsnPubSubServCfg != nil { if jsnPubSubServCfg.Enabled != nil { self.PubSubServerEnabled = *jsnPubSubServCfg.Enabled } } if jsnAliasesServCfg != nil { if jsnAliasesServCfg.Enabled != nil { self.AliasesServerEnabled = *jsnAliasesServCfg.Enabled } } if jsnRLSCfg != nil { if self.resourceLimiterCfg == nil { self.resourceLimiterCfg = new(ResourceLimiterConfig) } if self.resourceLimiterCfg.loadFromJsonCfg(jsnRLSCfg); err != nil { return err } } if jsnUserServCfg != nil { if jsnUserServCfg.Enabled != nil { self.UserServerEnabled = *jsnUserServCfg.Enabled } if jsnUserServCfg.Indexes != nil { self.UserServerIndexes = *jsnUserServCfg.Indexes } } if jsnMailerCfg != nil { if jsnMailerCfg.Server != nil { self.MailerServer = *jsnMailerCfg.Server } if jsnMailerCfg.Auth_user != nil { self.MailerAuthUser = *jsnMailerCfg.Auth_user } if jsnMailerCfg.Auth_password != nil { self.MailerAuthPass = *jsnMailerCfg.Auth_password } if jsnMailerCfg.From_address != nil { self.MailerFromAddr = *jsnMailerCfg.From_address } } if jsnSureTaxCfg != nil { // New config for SureTax if self.sureTaxCfg, err = NewSureTaxCfgWithDefaults(); err != nil { return err } if err := self.sureTaxCfg.loadFromJsonCfg(jsnSureTaxCfg); err != nil { return err } } return nil }
func (self *Mediator) RateCdr(storedCdr *utils.StoredCdr, sendToStats bool) error { storedCdr.MediationRunId = utils.DEFAULT_RUNID cdrRuns := []*utils.StoredCdr{storedCdr} // Start with initial storCdr, will add here all to be mediated attrsDC := utils.AttrDerivedChargers{Tenant: storedCdr.Tenant, Category: storedCdr.Category, Direction: storedCdr.Direction, Account: storedCdr.Account, Subject: storedCdr.Subject} var dcs utils.DerivedChargers if err := self.connector.GetDerivedChargers(attrsDC, &dcs); err != nil { errText := fmt.Sprintf("Could not get derived charging for cgrid %s, error: %s", storedCdr.CgrId, err.Error()) Logger.Err(errText) return errors.New(errText) } for _, dc := range dcs { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if fltrPass, _ := storedCdr.PassesFieldFilter(dcRunFilter); !fltrPass { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } dcReqTypeFld, _ := utils.NewRSRField(dc.ReqTypeField) dcDirFld, _ := utils.NewRSRField(dc.DirectionField) dcTenantFld, _ := utils.NewRSRField(dc.TenantField) dcCategoryFld, _ := utils.NewRSRField(dc.CategoryField) dcAcntFld, _ := utils.NewRSRField(dc.AccountField) dcSubjFld, _ := utils.NewRSRField(dc.SubjectField) dcDstFld, _ := utils.NewRSRField(dc.DestinationField) dcSTimeFld, _ := utils.NewRSRField(dc.SetupTimeField) dcATimeFld, _ := utils.NewRSRField(dc.AnswerTimeField) dcDurFld, _ := utils.NewRSRField(dc.UsageField) forkedCdr, err := storedCdr.ForkCdr(dc.RunId, dcReqTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, dcSTimeFld, dcATimeFld, dcDurFld, []*utils.RSRField{}, true) if err != nil { // Errors on fork, cannot calculate further, write that into db for later analysis self.cdrDb.SetRatedCdr(&utils.StoredCdr{CgrId: storedCdr.CgrId, CdrSource: utils.FORKED_CDR, MediationRunId: dc.RunId, Cost: -1}, err.Error()) // Cannot fork CDR, important just runid and error continue } cdrRuns = append(cdrRuns, forkedCdr) } for _, cdr := range cdrRuns { extraInfo := "" if err := self.rateCDR(cdr); err != nil { extraInfo = err.Error() } if !self.cgrCfg.MediatorStoreDisable { if err := self.cdrDb.SetRatedCdr(cdr, extraInfo); err != nil { Logger.Err(fmt.Sprintf("<Mediator> Could not record cost for cgrid: <%s>, ERROR: <%s>, cost: %f, extraInfo: %s", cdr.CgrId, err.Error(), cdr.Cost, extraInfo)) } } if sendToStats && self.stats != nil { // We send to stats only after saving to db since there are chances we cannot store and then no way to reproduce stats offline go func(cdr *utils.StoredCdr) { // Pass it by value since the variable will be overwritten by for if err := self.stats.AppendCDR(cdr, nil); err != nil { Logger.Err(fmt.Sprintf("Could not append cdr to stats (mediator): %s", err.Error())) } }(cdr) } } return nil }
func cdrLogAction(acc *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (err error) { defaultTemplate := map[string]utils.RSRFields{ "TOR": utils.ParseRSRFieldsMustCompile("balance_type", utils.INFIELD_SEP), "CdrHost": utils.ParseRSRFieldsMustCompile("^127.0.0.1", utils.INFIELD_SEP), "Direction": utils.ParseRSRFieldsMustCompile("direction", utils.INFIELD_SEP), "ReqType": utils.ParseRSRFieldsMustCompile("^"+utils.META_PREPAID, utils.INFIELD_SEP), "Tenant": utils.ParseRSRFieldsMustCompile("tenant", utils.INFIELD_SEP), "Account": utils.ParseRSRFieldsMustCompile("account", utils.INFIELD_SEP), "Subject": utils.ParseRSRFieldsMustCompile("account", utils.INFIELD_SEP), "Cost": utils.ParseRSRFieldsMustCompile("balance_value", utils.INFIELD_SEP), "MediationRunId": utils.ParseRSRFieldsMustCompile("^"+utils.META_DEFAULT, utils.INFIELD_SEP), } template := make(map[string]string) // overwrite default template if a.ExtraParameters != "" { if err = json.Unmarshal([]byte(a.ExtraParameters), &template); err != nil { return } for field, rsr := range template { defaultTemplate[field], err = utils.ParseRSRFields(rsr, utils.INFIELD_SEP) if err != nil { return err } } } // set stored cdr values var cdrs []*StoredCdr for _, action := range acs { if !utils.IsSliceMember([]string{DEBIT, DEBIT_RESET}, action.ActionType) || action.Balance == nil { continue // Only log specific actions } cdr := &StoredCdr{CdrSource: CDRLOG, SetupTime: time.Now(), AnswerTime: time.Now(), AccId: utils.GenUUID(), ExtraFields: make(map[string]string)} cdr.CgrId = utils.Sha1(cdr.AccId, cdr.SetupTime.String()) cdr.Usage = time.Duration(1) * time.Second elem := reflect.ValueOf(cdr).Elem() for key, rsrFlds := range defaultTemplate { parsedValue := parseTemplateValue(rsrFlds, acc, action) field := elem.FieldByName(key) if field.IsValid() && field.CanSet() { switch field.Kind() { case reflect.Float64: value, err := strconv.ParseFloat(parsedValue, 64) if err != nil { continue } field.SetFloat(value) case reflect.String: field.SetString(parsedValue) } } else { // invalid fields go in extraFields of CDR cdr.ExtraFields[key] = parsedValue } } //utils.Logger.Debug(fmt.Sprintf("account: %+v, action: %+v, balance: %+v", acc, action, action.Balance)) cdrs = append(cdrs, cdr) if cdrStorage == nil { // Only save if the cdrStorage is defined continue } if err := cdrStorage.SetCdr(cdr); err != nil { return err } if err := cdrStorage.SetRatedCdr(cdr); err != nil { return err } // FixMe //if err := cdrStorage.LogCallCost(); err != nil { // return err //} } b, _ := json.Marshal(cdrs) a.ExpirationString = string(b) // testing purpose only return }
func TestCdreCfgClone(t *testing.T) { cgrIdRsrs, _ := utils.ParseRSRFields("cgrid", utils.INFIELD_SEP) runIdRsrs, _ := utils.ParseRSRFields("mediation_runid", utils.INFIELD_SEP) emptyFields := []*CfgCdrField{} initContentFlds := []*CfgCdrField{ &CfgCdrField{Tag: "CgrId", Type: "cdrfield", CdrFieldId: "cgrid", Value: cgrIdRsrs}, &CfgCdrField{Tag: "RunId", Type: "cdrfield", CdrFieldId: "mediation_runid", Value: runIdRsrs}, } initCdreCfg := &CdreConfig{ CdrFormat: "csv", FieldSeparator: rune(','), DataUsageMultiplyFactor: 1.0, CostMultiplyFactor: 1.0, CostRoundingDecimals: -1, CostShiftDigits: 0, MaskDestId: "MASKED_DESTINATIONS", MaskLength: 0, ExportDir: "/var/log/cgrates/cdre", ContentFields: initContentFlds, } eClnContentFlds := []*CfgCdrField{ &CfgCdrField{Tag: "CgrId", Type: "cdrfield", CdrFieldId: "cgrid", Value: cgrIdRsrs}, &CfgCdrField{Tag: "RunId", Type: "cdrfield", CdrFieldId: "mediation_runid", Value: runIdRsrs}, } eClnCdreCfg := &CdreConfig{ CdrFormat: "csv", FieldSeparator: rune(','), DataUsageMultiplyFactor: 1.0, CostMultiplyFactor: 1.0, CostRoundingDecimals: -1, CostShiftDigits: 0, MaskDestId: "MASKED_DESTINATIONS", MaskLength: 0, ExportDir: "/var/log/cgrates/cdre", HeaderFields: emptyFields, ContentFields: eClnContentFlds, TrailerFields: emptyFields, } clnCdreCfg := initCdreCfg.Clone() if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { t.Errorf("Cloned result: %+v", clnCdreCfg) } initCdreCfg.DataUsageMultiplyFactor = 1024.0 if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { // MOdifying a field after clone should not affect cloned instance t.Errorf("Cloned result: %+v", clnCdreCfg) } initContentFlds[0].Tag = "Destination" if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { // MOdifying a field after clone should not affect cloned instance t.Errorf("Cloned result: %+v", clnCdreCfg) } clnCdreCfg.CostShiftDigits = 2 if initCdreCfg.CostShiftDigits != 0 { t.Error("Unexpected CostShiftDigits: ", initCdreCfg.CostShiftDigits) } clnCdreCfg.ContentFields[0].CdrFieldId = "destination" if initCdreCfg.ContentFields[0].CdrFieldId != "cgrid" { t.Error("Unexpected change of CdrFieldId: ", initCdreCfg.ContentFields[0].CdrFieldId) } }
// Returns MaxSessionTime for an event received in SessionManager, considering DerivedCharging for it func (rs *Responder) GetDerivedMaxSessionTime(ev *CDR, reply *float64) error { if rs.Bal != nil { return errors.New("unsupported method on the balancer") } cacheKey := utils.GET_DERIV_MAX_SESS_TIME + ev.CGRID + ev.RunID if item, err := rs.getCache().Get(cacheKey); err == nil && item != nil { if item.Value != nil { *reply = *(item.Value.(*float64)) } return item.Err } if ev.Subject == "" { ev.Subject = ev.Account } // replace user profile fields if err := LoadUserProfile(ev, utils.EXTRA_FIELDS); err != nil { rs.getCache().Cache(cacheKey, &CacheItem{Err: err}) return err } // replace aliases if err := LoadAlias( &AttrMatchingAlias{ Destination: ev.Destination, Direction: ev.Direction, Tenant: ev.Tenant, Category: ev.Category, Account: ev.Account, Subject: ev.Subject, Context: utils.ALIAS_CONTEXT_RATING, }, ev, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { rs.getCache().Cache(cacheKey, &CacheItem{Err: err}) return err } maxCallDuration := -1.0 attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT), Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)} dcs := &utils.DerivedChargers{} if err := rs.GetDerivedChargers(attrsDC, dcs); err != nil { rs.getCache().Cache(cacheKey, &CacheItem{Err: err}) return err } dcs, _ = dcs.AppendDefaultRun() for _, dc := range dcs.Chargers { if utils.IsSliceMember([]string{utils.META_RATED, utils.RATED}, ev.GetReqType(dc.RequestTypeField)) { // Only consider prepaid and pseudoprepaid for MaxSessionTime continue } runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if !dcRunFilter.FilterPasses(ev.FieldAsString(dcRunFilter)) { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } startTime, err := ev.GetSetupTime(utils.META_DEFAULT, rs.Timezone) if err != nil { rs.getCache().Cache(cacheKey, &CacheItem{Err: err}) return err } usage, err := ev.GetDuration(utils.META_DEFAULT) if err != nil { rs.getCache().Cache(cacheKey, &CacheItem{Err: err}) return err } if usage == 0 { usage = config.CgrConfig().MaxCallDuration } cd := &CallDescriptor{ CgrID: ev.GetCgrId(rs.Timezone), RunID: dc.RunID, TOR: ev.ToR, Direction: ev.GetDirection(dc.DirectionField), Tenant: ev.GetTenant(dc.TenantField), Category: ev.GetCategory(dc.CategoryField), Subject: ev.GetSubject(dc.SubjectField), Account: ev.GetAccount(dc.AccountField), Destination: ev.GetDestination(dc.DestinationField), TimeStart: startTime, TimeEnd: startTime.Add(usage), } var remainingDuration float64 err = rs.GetMaxSessionTime(cd, &remainingDuration) if err != nil { *reply = 0 rs.getCache().Cache(cacheKey, &CacheItem{Err: err}) return err } if utils.IsSliceMember([]string{utils.META_POSTPAID, utils.POSTPAID}, ev.GetReqType(dc.RequestTypeField)) { // Only consider prepaid and pseudoprepaid for MaxSessionTime, do it here for unauthorized destination error check continue } // Set maxCallDuration, smallest out of all forked sessions if maxCallDuration == -1.0 { // first time we set it /not initialized yet maxCallDuration = remainingDuration } else if maxCallDuration > remainingDuration { maxCallDuration = remainingDuration } } rs.getCache().Cache(cacheKey, &CacheItem{Value: maxCallDuration}) *reply = maxCallDuration return nil }
// Process Authorize request from OpenSIPS and communicate back maxdur func (osm *OsipsSessionManager) OnAuthorize(osipsDagram *osipsdagram.OsipsEvent) { ev, _ := NewOsipsEvent(osipsDagram) if ev.MissingParameter() { cmdNotify := fmt.Sprintf(":cache_store:\nlocal\n%s/cgr_notify\n%s\n2\n\n", ev.GetUUID(), utils.ERR_MANDATORY_IE_MISSING) if reply, err := osm.miConn.SendCommand([]byte(cmdNotify)); err != nil || !bytes.HasPrefix(reply, []byte("200 OK")) { engine.Logger.Err(fmt.Sprintf("Failed setting cgr_notify variable for accid: %s, err: %v, reply: %s", ev.GetUUID(), err, string(reply))) } return } var maxCallDuration time.Duration // This will be the maximum duration this channel will be allowed to last var durInitialized bool attrsDC := utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT), Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)} var dcs utils.DerivedChargers if err := osm.rater.GetDerivedChargers(attrsDC, &dcs); err != nil { engine.Logger.Err(fmt.Sprintf("<SM-OpenSIPS> OnAuthorize: could not get derived charging for event %s: %s", ev.GetUUID(), err.Error())) cmdNotify := fmt.Sprintf(":cache_store:\nlocal\n%s/cgr_notify\n%s\n2\n\n", ev.GetUUID(), utils.ERR_SERVER_ERROR) if reply, err := osm.miConn.SendCommand([]byte(cmdNotify)); err != nil || !bytes.HasPrefix(reply, []byte("200 OK")) { engine.Logger.Err(fmt.Sprintf("Failed setting cgr_notify variable for accid: %s, err: %v, reply: %s", ev.GetUUID(), err, string(reply))) } return } dcs, _ = dcs.AppendDefaultRun() for _, dc := range dcs { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if fltrPass, _ := ev.PassesFieldFilter(dcRunFilter); !fltrPass { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } startTime, err := ev.GetSetupTime(utils.META_DEFAULT) if err != nil { engine.Logger.Err("Error parsing answer event start time, using time.Now!") startTime = time.Now() } cd := engine.CallDescriptor{ Direction: ev.GetDirection(dc.DirectionField), Tenant: ev.GetTenant(dc.TenantField), Category: ev.GetCategory(dc.CategoryField), Subject: ev.GetSubject(dc.SubjectField), Account: ev.GetAccount(dc.AccountField), Destination: ev.GetDestination(dc.DestinationField), TimeStart: startTime, TimeEnd: startTime.Add(osm.cgrCfg.SMMaxCallDuration), } var remainingDurationFloat float64 err = osm.rater.GetMaxSessionTime(cd, &remainingDurationFloat) if err != nil { engine.Logger.Err(fmt.Sprintf("Could not get max session time for %s: %v", ev.GetUUID(), err)) cmdNotify := fmt.Sprintf(":cache_store:\nlocal\n%s/cgr_notify\n%s\n2\n\n", ev.GetUUID(), utils.ERR_SERVER_ERROR) if reply, err := osm.miConn.SendCommand([]byte(cmdNotify)); err != nil || !bytes.HasPrefix(reply, []byte("200 OK")) { engine.Logger.Err(fmt.Sprintf("Failed setting cgr_notify variable for accid: %s, err: %v, reply: %s", ev.GetUUID(), err, string(reply))) } return } remainingDuration := time.Duration(remainingDurationFloat) // Set maxCallDuration, smallest out of all forked sessions if !durInitialized { // first time we set it /not initialized yet maxCallDuration = remainingDuration durInitialized = true } else if maxCallDuration > remainingDuration { maxCallDuration = remainingDuration } } if maxCallDuration <= osm.cgrCfg.SMMinCallDuration { cmdNotify := fmt.Sprintf(":cache_store:\nlocal\n%s/cgr_notify\n%s\n2\n\n", ev.GetUUID(), OSIPS_INSUFFICIENT_FUNDS) if reply, err := osm.miConn.SendCommand([]byte(cmdNotify)); err != nil || !bytes.HasPrefix(reply, []byte("200 OK")) { engine.Logger.Err(fmt.Sprintf("Failed setting cgr_notify variable for accid: %s, err: %v, reply: %s", ev.GetUUID(), err, string(reply))) } return } cmdMaxDur := fmt.Sprintf(":cache_store:\nlocal\n%s/cgr_maxdur\n%d\n\n", ev.GetUUID(), int(maxCallDuration.Seconds())) if reply, err := osm.miConn.SendCommand([]byte(cmdMaxDur)); err != nil || !bytes.HasPrefix(reply, []byte("200 OK")) { engine.Logger.Err(fmt.Sprintf("Failed setting cgr_maxdur variable for accid: %s, err: %v, reply: %s", ev.GetUUID(), err, string(reply))) } cmdNotify := fmt.Sprintf(":cache_store:\nlocal\n%s/cgr_notify\n%s\n", ev.GetUUID(), OSIPS_AUTH_OK) if reply, err := osm.miConn.SendCommand([]byte(cmdNotify)); err != nil || !bytes.HasPrefix(reply, []byte("200 OK")) { engine.Logger.Err(fmt.Sprintf("Failed setting cgr_notify variable for accid: %s, err: %v, reply: %s", ev.GetUUID(), err, string(reply))) } }
// Loads/re-loads data from json config object func (self *SureTaxCfg) loadFromJsonCfg(jsnCfg *SureTaxJsonCfg) error { var err error if jsnCfg.Url != nil { self.Url = *jsnCfg.Url } if jsnCfg.Client_number != nil { self.ClientNumber = *jsnCfg.Client_number } if jsnCfg.Validation_key != nil { self.ValidationKey = *jsnCfg.Validation_key } if jsnCfg.Business_unit != nil { self.BusinessUnit = *jsnCfg.Business_unit } if jsnCfg.Timezone != nil { if self.Timezone, err = time.LoadLocation(*jsnCfg.Timezone); err != nil { return err } } if jsnCfg.Include_local_cost != nil { self.IncludeLocalCost = *jsnCfg.Include_local_cost } if jsnCfg.Return_file_code != nil { self.ReturnFileCode = *jsnCfg.Return_file_code } if jsnCfg.Response_group != nil { self.ResponseGroup = *jsnCfg.Response_group } if jsnCfg.Response_type != nil { self.ResponseType = *jsnCfg.Response_type } if jsnCfg.Regulatory_code != nil { self.RegulatoryCode = *jsnCfg.Regulatory_code } if jsnCfg.Client_tracking != nil { if self.ClientTracking, err = utils.ParseRSRFields(*jsnCfg.Client_tracking, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Customer_number != nil { if self.CustomerNumber, err = utils.ParseRSRFields(*jsnCfg.Customer_number, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Orig_number != nil { if self.OrigNumber, err = utils.ParseRSRFields(*jsnCfg.Orig_number, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Term_number != nil { if self.TermNumber, err = utils.ParseRSRFields(*jsnCfg.Term_number, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Bill_to_number != nil { if self.BillToNumber, err = utils.ParseRSRFields(*jsnCfg.Bill_to_number, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Zipcode != nil { if self.Zipcode, err = utils.ParseRSRFields(*jsnCfg.Zipcode, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Plus4 != nil { if self.Plus4, err = utils.ParseRSRFields(*jsnCfg.Plus4, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.P2PZipcode != nil { if self.P2PZipcode, err = utils.ParseRSRFields(*jsnCfg.P2PZipcode, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.P2PPlus4 != nil { if self.P2PPlus4, err = utils.ParseRSRFields(*jsnCfg.P2PPlus4, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Units != nil { if self.Units, err = utils.ParseRSRFields(*jsnCfg.Units, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Unit_type != nil { if self.UnitType, err = utils.ParseRSRFields(*jsnCfg.Unit_type, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Tax_included != nil { if self.TaxIncluded, err = utils.ParseRSRFields(*jsnCfg.Tax_included, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Tax_situs_rule != nil { if self.TaxSitusRule, err = utils.ParseRSRFields(*jsnCfg.Tax_situs_rule, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Trans_type_code != nil { if self.TransTypeCode, err = utils.ParseRSRFields(*jsnCfg.Trans_type_code, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Sales_type_code != nil { if self.SalesTypeCode, err = utils.ParseRSRFields(*jsnCfg.Sales_type_code, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Tax_exemption_code_list != nil { if self.TaxExemptionCodeList, err = utils.ParseRSRFields(*jsnCfg.Tax_exemption_code_list, utils.INFIELD_SEP); err != nil { return err } } return nil }
func (self *CdrServer) deriveCdrs(cdr *CDR) ([]*CDR, error) { dfltCDRRun := cdr.Clone() cdrRuns := []*CDR{dfltCDRRun} if cdr.RunID != utils.MetaRaw { // Only derive *raw CDRs return cdrRuns, nil } dfltCDRRun.RunID = utils.META_DEFAULT // Rewrite *raw with *default since we have it as first run if err := LoadUserProfile(cdr, utils.EXTRA_FIELDS); err != nil { return nil, err } if err := LoadAlias(&AttrMatchingAlias{ Destination: cdr.Destination, Direction: cdr.Direction, Tenant: cdr.Tenant, Category: cdr.Category, Account: cdr.Account, Subject: cdr.Subject, Context: utils.ALIAS_CONTEXT_RATING, }, cdr, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { return nil, err } attrsDC := &utils.AttrDerivedChargers{Tenant: cdr.Tenant, Category: cdr.Category, Direction: cdr.Direction, Account: cdr.Account, Subject: cdr.Subject, Destination: cdr.Destination} var dcs utils.DerivedChargers if err := self.rals.Call("Responder.GetDerivedChargers", attrsDC, &dcs); err != nil { utils.Logger.Err(fmt.Sprintf("Could not get derived charging for cgrid %s, error: %s", cdr.CGRID, err.Error())) return nil, err } for _, dc := range dcs.Chargers { runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if !dcRunFilter.FilterPasses(cdr.FieldAsString(dcRunFilter)) { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } dcRequestTypeFld, _ := utils.NewRSRField(dc.RequestTypeField) dcDirFld, _ := utils.NewRSRField(dc.DirectionField) dcTenantFld, _ := utils.NewRSRField(dc.TenantField) dcCategoryFld, _ := utils.NewRSRField(dc.CategoryField) dcAcntFld, _ := utils.NewRSRField(dc.AccountField) dcSubjFld, _ := utils.NewRSRField(dc.SubjectField) dcDstFld, _ := utils.NewRSRField(dc.DestinationField) dcSTimeFld, _ := utils.NewRSRField(dc.SetupTimeField) dcPddFld, _ := utils.NewRSRField(dc.PDDField) dcATimeFld, _ := utils.NewRSRField(dc.AnswerTimeField) dcDurFld, _ := utils.NewRSRField(dc.UsageField) dcSupplFld, _ := utils.NewRSRField(dc.SupplierField) dcDCauseFld, _ := utils.NewRSRField(dc.DisconnectCauseField) dcRatedFld, _ := utils.NewRSRField(dc.RatedField) dcCostFld, _ := utils.NewRSRField(dc.CostField) forkedCdr, err := cdr.ForkCdr(dc.RunID, dcRequestTypeFld, dcDirFld, dcTenantFld, dcCategoryFld, dcAcntFld, dcSubjFld, dcDstFld, dcSTimeFld, dcPddFld, dcATimeFld, dcDurFld, dcSupplFld, dcDCauseFld, dcRatedFld, dcCostFld, []*utils.RSRField{}, true, self.cgrCfg.DefaultTimezone) if err != nil { utils.Logger.Err(fmt.Sprintf("Could not fork CGR with cgrid %s, run: %s, error: %s", cdr.CGRID, dc.RunID, err.Error())) continue // do not add it to the forked CDR list } if !forkedCdr.Rated { forkedCdr.Cost = -1.0 // Make sure that un-rated CDRs start with Cost -1 } cdrRuns = append(cdrRuns, forkedCdr) } return cdrRuns, nil }
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.Dry_run != nil { self.DryRun = *jsnCfg.Dry_run } if jsnCfg.Cdrs != nil { self.Cdrs = *jsnCfg.Cdrs } 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.Timezone != nil { self.Timezone = *jsnCfg.Timezone } if jsnCfg.Run_delay != nil { self.RunDelay = time.Duration(*jsnCfg.Run_delay) * time.Second } if jsnCfg.Max_open_files != nil { self.MaxOpenFiles = *jsnCfg.Max_open_files } 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.Failed_calls_prefix != nil { self.FailedCallsPrefix = *jsnCfg.Failed_calls_prefix } if jsnCfg.Cdr_source_id != nil { self.CdrSourceId = *jsnCfg.Cdr_source_id } if jsnCfg.Cdr_filter != nil { if self.CdrFilter, err = utils.ParseRSRFields(*jsnCfg.Cdr_filter, utils.INFIELD_SEP); err != nil { return err } } if jsnCfg.Continue_on_success != nil { self.ContinueOnSuccess = *jsnCfg.Continue_on_success } if jsnCfg.Partial_record_cache != nil { if self.PartialRecordCache, err = utils.ParseDurationWithSecs(*jsnCfg.Partial_record_cache); err != nil { return err } } 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 }
// Returns MaxSessionTime for an event received in SessionManager, considering DerivedCharging for it func (rs *Responder) GetDerivedMaxSessionTime(ev *StoredCdr, reply *float64) error { if rs.Bal != nil { return errors.New("unsupported method on the balancer") } if ev.Subject == "" { ev.Subject = ev.Account } if upData, err := LoadUserProfile(ev, "ExtraFields"); err != nil { return err } else { udRcv := upData.(*StoredCdr) *ev = *udRcv } maxCallDuration := -1.0 attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT), Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)} var dcs utils.DerivedChargers if err := rs.GetDerivedChargers(attrsDC, &dcs); err != nil { return err } dcs, _ = dcs.AppendDefaultRun() for _, dc := range dcs { if utils.IsSliceMember([]string{utils.META_RATED, utils.RATED}, ev.GetReqType(dc.ReqTypeField)) { // Only consider prepaid and pseudoprepaid for MaxSessionTime continue } runFilters, _ := utils.ParseRSRFields(dc.RunFilters, utils.INFIELD_SEP) matchingAllFilters := true for _, dcRunFilter := range runFilters { if fltrPass, _ := ev.PassesFieldFilter(dcRunFilter); !fltrPass { matchingAllFilters = false break } } if !matchingAllFilters { // Do not process the derived charger further if not all filters were matched continue } startTime, err := ev.GetSetupTime(utils.META_DEFAULT, rs.Timezone) if err != nil { return err } usage, err := ev.GetDuration(utils.META_DEFAULT) if err != nil { return err } if usage == 0 { usage = config.CgrConfig().MaxCallDuration } cd := &CallDescriptor{ Direction: ev.GetDirection(dc.DirectionField), Tenant: ev.GetTenant(dc.TenantField), Category: ev.GetCategory(dc.CategoryField), Subject: ev.GetSubject(dc.SubjectField), Account: ev.GetAccount(dc.AccountField), Destination: ev.GetDestination(dc.DestinationField), TimeStart: startTime, TimeEnd: startTime.Add(usage), } var remainingDuration float64 err = rs.GetMaxSessionTime(cd, &remainingDuration) if err != nil { *reply = 0 return err } if utils.IsSliceMember([]string{utils.META_POSTPAID, utils.POSTPAID}, ev.GetReqType(dc.ReqTypeField)) { // Only consider prepaid and pseudoprepaid for MaxSessionTime continue } // Set maxCallDuration, smallest out of all forked sessions if maxCallDuration == -1.0 { // first time we set it /not initialized yet maxCallDuration = remainingDuration } else if maxCallDuration > remainingDuration { maxCallDuration = remainingDuration } } *reply = maxCallDuration return nil }
func cdrLogAction(acc *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (err error) { defaultTemplate := map[string]utils.RSRFields{ utils.TOR: utils.ParseRSRFieldsMustCompile("BalanceType", utils.INFIELD_SEP), utils.CDRHOST: utils.ParseRSRFieldsMustCompile("^127.0.0.1", utils.INFIELD_SEP), utils.DIRECTION: utils.ParseRSRFieldsMustCompile("Directions", utils.INFIELD_SEP), utils.REQTYPE: utils.ParseRSRFieldsMustCompile("^"+utils.META_PREPAID, utils.INFIELD_SEP), utils.TENANT: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP), utils.ACCOUNT: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP), utils.SUBJECT: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP), utils.COST: utils.ParseRSRFieldsMustCompile("ActionValue", utils.INFIELD_SEP), } template := make(map[string]string) // overwrite default template if a.ExtraParameters != "" { if err = json.Unmarshal([]byte(a.ExtraParameters), &template); err != nil { return } for field, rsr := range template { defaultTemplate[field], err = utils.ParseRSRFields(rsr, utils.INFIELD_SEP) if err != nil { return err } } } // set stored cdr values var cdrs []*CDR for _, action := range acs { if !utils.IsSliceMember([]string{DEBIT, DEBIT_RESET, TOPUP, TOPUP_RESET}, action.ActionType) || action.Balance == nil { continue // Only log specific actions } cdr := &CDR{RunID: action.ActionType, Source: CDRLOG, SetupTime: time.Now(), AnswerTime: time.Now(), OriginID: utils.GenUUID(), ExtraFields: make(map[string]string)} cdr.CGRID = utils.Sha1(cdr.OriginID, cdr.SetupTime.String()) cdr.Usage = time.Duration(1) * time.Second elem := reflect.ValueOf(cdr).Elem() for key, rsrFlds := range defaultTemplate { parsedValue := parseTemplateValue(rsrFlds, acc, action) field := elem.FieldByName(key) if field.IsValid() && field.CanSet() { switch field.Kind() { case reflect.Float64: value, err := strconv.ParseFloat(parsedValue, 64) if err != nil { continue } field.SetFloat(value) case reflect.String: field.SetString(parsedValue) } } else { // invalid fields go in extraFields of CDR cdr.ExtraFields[key] = parsedValue } } cdrs = append(cdrs, cdr) if cdrStorage == nil { // Only save if the cdrStorage is defined continue } if err := cdrStorage.SetCDR(cdr, true); err != nil { return err } } b, _ := json.Marshal(cdrs) a.ExpirationString = string(b) // testing purpose only return }