From 99a244060ecd24a8d2732fab8df5c6ad68377d2c Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 27 May 2015 20:04:03 +0300 Subject: [PATCH] unified tp_reader and tp_data files --- engine/model_helpers.go | 124 +++++++++ engine/storage_csv.go | 107 ++++++-- engine/storage_interface.go | 56 ++-- engine/storage_sql.go | 118 ++------- engine/tp_data.go | 392 ---------------------------- engine/tp_reader.go | 508 ++++++++++++++++++++++++++++++++++-- utils/consts.go | 14 - 7 files changed, 751 insertions(+), 568 deletions(-) delete mode 100644 engine/tp_data.go diff --git a/engine/model_helpers.go b/engine/model_helpers.go index 2bbc07b08..96763de04 100644 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -50,6 +50,20 @@ func csvLoad(s interface{}, values []string) (interface{}, error) { return elem.Interface(), nil } +func getColumnCount(s interface{}) int { + st := reflect.TypeOf(s) + numFields := st.NumField() + count := 0 + for i := 0; i < numFields; i++ { + field := st.Field(i) + index := field.Tag.Get("index") + if index != "" { + count++ + } + } + return count +} + type TpDestinations []*TpDestination func (tps TpDestinations) GetDestinations() (map[string]*Destination, error) { @@ -116,3 +130,113 @@ func (tps TpRates) GetRates() (map[string]*utils.TPRate, error) { } return rates, nil } + +type TpDestinationRates []*TpDestinationRate + +func (tps TpDestinationRates) GetDestinationRates() (map[string]*utils.TPDestinationRate, error) { + rts := make(map[string]*utils.TPDestinationRate) + for _, tpDr := range tps { + dr := &utils.TPDestinationRate{ + DestinationRateId: tpDr.Tag, + DestinationRates: []*utils.DestinationRate{ + &utils.DestinationRate{ + DestinationId: tpDr.DestinationsTag, + RateId: tpDr.RatesTag, + RoundingMethod: tpDr.RoundingMethod, + RoundingDecimals: tpDr.RoundingDecimals, + MaxCost: tpDr.MaxCost, + MaxCostStrategy: tpDr.MaxCostStrategy, + }, + }, + } + existingDR, exists := rts[tpDr.Tag] + if exists { + existingDR.DestinationRates = append(existingDR.DestinationRates, dr.DestinationRates[0]) + } else { + existingDR = dr + } + rts[tpDr.Tag] = existingDR + + } + return rts, nil +} + +type TpRatingPlans []*TpRatingPlan + +func (tps TpRatingPlans) GetRatingPlans() (map[string][]*utils.TPRatingPlanBinding, error) { + rpbns := make(map[string][]*utils.TPRatingPlanBinding) + + for _, tpRp := range tps { + rpb := &utils.TPRatingPlanBinding{ + DestinationRatesId: tpRp.DestratesTag, + TimingId: tpRp.TimingTag, + Weight: tpRp.Weight, + } + if _, exists := rpbns[tpRp.Tag]; exists { + rpbns[tpRp.Tag] = append(rpbns[tpRp.Tag], rpb) + } else { // New + rpbns[tpRp.Tag] = []*utils.TPRatingPlanBinding{rpb} + } + } + return rpbns, nil +} + +func GetRateInterval(rpl *utils.TPRatingPlanBinding, dr *utils.DestinationRate) (i *RateInterval) { + i = &RateInterval{ + Timing: &RITiming{ + Years: rpl.Timing().Years, + Months: rpl.Timing().Months, + MonthDays: rpl.Timing().MonthDays, + WeekDays: rpl.Timing().WeekDays, + StartTime: rpl.Timing().StartTime, + }, + Weight: rpl.Weight, + Rating: &RIRate{ + ConnectFee: dr.Rate.RateSlots[0].ConnectFee, + RoundingMethod: dr.RoundingMethod, + RoundingDecimals: dr.RoundingDecimals, + MaxCost: dr.MaxCost, + MaxCostStrategy: dr.MaxCostStrategy, + }, + } + for _, rl := range dr.Rate.RateSlots { + i.Rating.Rates = append(i.Rating.Rates, &Rate{ + GroupIntervalStart: rl.GroupIntervalStartDuration(), + Value: rl.Rate, + RateIncrement: rl.RateIncrementDuration(), + RateUnit: rl.RateUnitDuration(), + }) + } + return +} + +type TpRatingProfiles []*TpRatingProfile + +func (tps TpRatingProfiles) GetRatingProfiles() (map[string]*utils.TPRatingProfile, error) { + rpfs := make(map[string]*utils.TPRatingProfile) + for _, tpRpf := range tps { + + rp := &utils.TPRatingProfile{ + TPid: tpRpf.Tpid, + LoadId: tpRpf.Loadid, + Direction: tpRpf.Direction, + Tenant: tpRpf.Tenant, + Category: tpRpf.Category, + Subject: tpRpf.Subject, + } + ra := &utils.TPRatingActivation{ + ActivationTime: tpRpf.ActivationTime, + RatingPlanId: tpRpf.RatingPlanTag, + FallbackSubjects: tpRpf.FallbackSubjects, + CdrStatQueueIds: tpRpf.CdrStatQueueIds, + } + if existingRpf, exists := rpfs[rp.KeyId()]; !exists { + rp.RatingPlanActivations = []*utils.TPRatingActivation{ra} + rpfs[rp.KeyId()] = rp + } else { // Exists, update + existingRpf.RatingPlanActivations = append(existingRpf.RatingPlanActivations, ra) + } + + } + return rpfs, nil +} diff --git a/engine/storage_csv.go b/engine/storage_csv.go index 1c229f783..1170802b3 100644 --- a/engine/storage_csv.go +++ b/engine/storage_csv.go @@ -62,7 +62,7 @@ func openStringCSVStorage(data string, comma rune, nrFields int) (csvReader *csv } func (csvs *CSVStorage) GetTpTimings(string, string) ([]*TpTiming, error) { - csvReader, fp, err := csvs.readerFunc(csvs.timingsFn, csvs.sep, utils.TIMINGS_NRCOLS) + csvReader, fp, err := csvs.readerFunc(csvs.timingsFn, csvs.sep, getColumnCount(TpTiming{})) if err != nil { log.Print("Could not load timings file: ", err) // allow writing of the other values @@ -84,7 +84,7 @@ func (csvs *CSVStorage) GetTpTimings(string, string) ([]*TpTiming, error) { } func (csvs *CSVStorage) GetTpDestinations(tpid, tag string) ([]*TpDestination, error) { - csvReader, fp, err := csvs.readerFunc(csvs.destinationsFn, csvs.sep, utils.DESTINATIONS_NRCOLS) + csvReader, fp, err := csvs.readerFunc(csvs.destinationsFn, csvs.sep, getColumnCount(TpDestination{})) if err != nil { log.Print("Could not load destinations file: ", err) // allow writing of the other values @@ -107,7 +107,7 @@ func (csvs *CSVStorage) GetTpDestinations(tpid, tag string) ([]*TpDestination, e } func (csvs *CSVStorage) GetTpRates(tpid, tag string) ([]*TpRate, error) { - csvReader, fp, err := csvs.readerFunc(csvs.ratesFn, csvs.sep, utils.RATES_NRCOLS) + csvReader, fp, err := csvs.readerFunc(csvs.ratesFn, csvs.sep, getColumnCount(TpRate{})) if err != nil { log.Print("Could not load rates file: ", err) // allow writing of the other values @@ -129,45 +129,102 @@ func (csvs *CSVStorage) GetTpRates(tpid, tag string) ([]*TpRate, error) { return tpRates, nil } -func (csvs *CSVStorage) GetTpDestinationRates(string, string, *utils.Paginator) (map[string]*utils.TPDestinationRate, error) { +func (csvs *CSVStorage) GetTpDestinationRates(tpid, tag string, p *utils.Paginator) ([]*TpDestinationRate, error) { + csvReader, fp, err := csvs.readerFunc(csvs.destinationratesFn, csvs.sep, getColumnCount(TpDestinationRate{})) + if err != nil { + log.Print("Could not load destination_rates file: ", err) + // allow writing of the other values + return nil + } + if fp != nil { + defer fp.Close() + } + var tpDestinationRates []*TpDestinationRate + for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { + if tpRate, err := csvLoad(TpDestinationRate{}, record); err != nil { + return nil, err + } else { + tp := tpRate.(TpDestinationRate) + tpDestinationRates = append(tpDestinationRates, &tp) + } + //log.Printf("%+v\n", tpRate) + } + return tpDestinationRates, nil +} + +func (csvs *CSVStorage) GetTpRatingPlans(tpid, tag string, p *utils.Paginator) ([]*TpRatingPlan, error) { + csvReader, fp, err := csvs.readerFunc(csvs.destinationratetimingsFn, csvs.sep, getColumnCount(TpRatingPlan{})) + if err != nil { + log.Print("Could not load rate plans file: ", err) + // allow writing of the other values + return nil + } + if fp != nil { + defer fp.Close() + } + var tpRatingPlans []*TpRatingPlan + for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { + if tpRate, err := csvLoad(TpRatingPlan{}, record); err != nil { + return nil, err + } else { + tp := tpRate.(TpRatingPlan) + tpRatingPlans = append(tpRatingPlans, &tp) + } + //log.Printf("%+v\n", tpRate) + } + return tpRatingPlans, nil +} + +func (csvs *CSVStorage) GetTpRatingProfiles(filter *utils.TPRatingProfile) ([]*TpRatingProfile, error) { + csvReader, fp, err := csvs.readerFunc(csvs.ratingprofilesFn, csvs.sep, getColumnCount(TpRatingProfile{})) + if err != nil { + log.Print("Could not load rating profiles file: ", err) + // allow writing of the other values + return nil + } + if fp != nil { + defer fp.Close() + } + var tpRatingProfiles []*TpRatingProfile + for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { + if tpRate, err := csvLoad(TpRatingProfile{}, record); err != nil { + return nil, err + } else { + tp := tpRate.(TpRatingProfile) + tpRatingProfiles = append(tpRatingProfiles, &tp) + } + //log.Printf("%+v\n", tpRate) + } + return tpRatingProfiles, nil +} + +func (csvs *CSVStorage) GetTpSharedGroups(tpid, tag string) ([]*TpSharedGroup, error) { return nil, nil } -func (csvs *CSVStorage) GetTpRatingPlans(string, string, *utils.Paginator) (map[string][]*utils.TPRatingPlanBinding, error) { +func (csvs *CSVStorage) GetTpCdrStats(tpid, tag string) ([]*TpCdrStat, error) { return nil, nil } -func (csvs *CSVStorage) GetTpRatingProfiles(*utils.TPRatingProfile) (map[string]*utils.TPRatingProfile, error) { +func (csvs *CSVStorage) GetTpDerivedChargers(filter *utils.TPDerivedChargers) ([]*TpDerivedCharger, error) { return nil, nil } -func (csvs *CSVStorage) GetTpSharedGroups(string, string) (map[string][]*utils.TPSharedGroup, error) { +func (csvs *CSVStorage) GetTpLCRs(tpid, tag string) ([]*TpLcrRules, error) { return nil, nil } + +func (csvs *CSVStorage) GetTpActions(tpid, tag string) ([]*TpAction, error) { return nil, nil } -func (csvs *CSVStorage) GetTpCdrStats(string, string) (map[string][]*utils.TPCdrStat, error) { +func (csvs *CSVStorage) GetTPActionTimings(tpid, tag string) ([]*TpActionPlan, error) { return nil, nil } -func (csvs *CSVStorage) GetTpDerivedChargers(*utils.TPDerivedChargers) (map[string]*utils.TPDerivedChargers, error) { +func (csvs *CSVStorage) GetTpActionTriggers(tpid, tag string) ([]*TpActionTrigger, error) { return nil, nil } -func (csvs *CSVStorage) GetTpLCRs(string, string) (map[string]*LCR, error) { return nil, nil } - -func (csvs *CSVStorage) GetTpActions(string, string) (map[string][]*utils.TPAction, error) { - return nil, nil -} - -func (csvs *CSVStorage) GetTPActionTimings(string, string) (map[string][]*utils.TPActionTiming, error) { - return nil, nil -} - -func (csvs *CSVStorage) GetTpActionTriggers(string, string) (map[string][]*utils.TPActionTrigger, error) { - return nil, nil -} - -func (csvs *CSVStorage) GetTpAccountActions(*utils.TPAccountActions) (map[string]*utils.TPAccountActions, error) { +func (csvs *CSVStorage) GetTpAccountActions(filter []*TpAccountAction) ([]*TpAccountAction, error) { return nil, nil } @@ -175,6 +232,6 @@ func (csvs *CSVStorage) GetTPIds() ([]string, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (csvs *CSVStorage) GetTPTableIds(string, string, utils.TPDistinctIds, map[string]string, *utils.Paginator) ([]string, error) { +func (csvs *CSVStorage) GetTPTableIds(tpid, table string, distinct utils.TPDistinctIds, filters map[string]string, p *utils.Paginator) ([]string, error) { return nil, errors.New(utils.ERR_NOT_IMPLEMENTED) } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 64e5b47b4..eb82ac7b5 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -135,40 +135,40 @@ type LoadStorage interface { } type LoadReader interface { - GetTPIds() ([]string, error) - GetTPTableIds(string, string, utils.TPDistinctIds, map[string]string, *utils.Paginator) ([]string, error) + GetTpIds() ([]string, error) + GetTpTableIds(string, string, utils.TPDistinctIds, map[string]string, *utils.Paginator) ([]string, error) GetTpTimings(string, string) ([]*TpTiming, error) GetTpDestinations(string, string) ([]*TpDestination, error) GetTpRates(string, string) ([]*TpRate, error) - GetTpDestinationRates(string, string, *utils.Paginator) (map[string]*utils.TPDestinationRate, error) - GetTpRatingPlans(string, string, *utils.Paginator) (map[string][]*utils.TPRatingPlanBinding, error) - GetTpRatingProfiles(*utils.TPRatingProfile) (map[string]*utils.TPRatingProfile, error) - GetTpSharedGroups(string, string) (map[string][]*utils.TPSharedGroup, error) - GetTpCdrStats(string, string) (map[string][]*utils.TPCdrStat, error) - GetTpDerivedChargers(*utils.TPDerivedChargers) (map[string]*utils.TPDerivedChargers, error) - GetTpLCRs(string, string) (map[string]*LCR, error) - GetTpActions(string, string) (map[string][]*utils.TPAction, error) - GetTPActionTimings(string, string) (map[string][]*utils.TPActionTiming, error) - GetTpActionTriggers(string, string) (map[string][]*utils.TPActionTrigger, error) - GetTpAccountActions(*utils.TPAccountActions) (map[string]*utils.TPAccountActions, error) + GetTpDestinationRates(string, string, *utils.Paginator) ([]*TpDestinationRate, error) + GetTpRatingPlans(string, string, *utils.Paginator) ([]*TpRatingPlan, error) + GetTpRatingProfiles(*utils.TPRatingProfile) ([]*TpRatingProfile, error) + GetTpSharedGroups(string, string) ([]*TpSharedGroup, error) + GetTpCdrStats(string, string) ([]*TpCdrStat, error) + GetTpDerivedChargers(*utils.TPDerivedChargers) ([]*TpDerivedCharger, error) + GetTpLCRs(string, string) ([]*TpLcrRules, error) + GetTpActions(string, string) ([]*TpAction, error) + GetTpActionTimings(string, string) ([]*TpActionPlan, error) + GetTpActionTriggers(string, string) ([]*TpActionTrigger, error) + GetTpAccountActions(*utils.TPAccountActions) ([]*TpAccountAction, error) } type LoadWriter interface { - RemTPData(string, string, ...string) error - SetTPTiming(*utils.ApierTPTiming) error - SetTPDestination(string, *Destination) error - SetTPRates(string, map[string][]*utils.RateSlot) error - SetTPDestinationRates(string, map[string][]*utils.DestinationRate) error - SetTPRatingPlans(string, map[string][]*utils.TPRatingPlanBinding) error - SetTPRatingProfiles(string, map[string]*utils.TPRatingProfile) error - SetTPSharedGroups(string, map[string][]*utils.TPSharedGroup) error - SetTPCdrStats(string, map[string][]*utils.TPCdrStat) error - SetTPDerivedChargers(string, map[string][]*utils.TPDerivedCharger) error - SetTPLCRs(string, map[string]*LCR) error - SetTPActions(string, map[string][]*utils.TPAction) error - SetTPActionTimings(string, map[string][]*utils.TPActionTiming) error - SetTPActionTriggers(string, map[string][]*utils.TPActionTrigger) error - SetTPAccountActions(string, map[string]*utils.TPAccountActions) error + RemTpData(string, string, ...string) error + SetTpTiming(*utils.ApierTPTiming) error + SetTpDestination(string, *Destination) error + SetTpRates(string, map[string][]*utils.RateSlot) error + SetTpDestinationRates(string, map[string][]*utils.DestinationRate) error + SetTpRatingPlans(string, map[string][]*utils.TPRatingPlanBinding) error + SetTpRatingProfiles(string, map[string]*utils.TPRatingProfile) error + SetTpSharedGroups(string, map[string][]*utils.TPSharedGroup) error + SetTpCdrStats(string, map[string][]*utils.TPCdrStat) error + SetTpDerivedChargers(string, map[string][]*utils.TPDerivedCharger) error + SetTpLCRs(string, map[string]*LCR) error + SetTpActions(string, map[string][]*utils.TPAction) error + SetTpActionTimings(string, map[string][]*utils.TPActionTiming) error + SetTpActionTriggers(string, map[string][]*utils.TPActionTrigger) error + SetTpAccountActions(string, map[string]*utils.TPAccountActions) error } type Marshaler interface { diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 4b422afd3..ffd23114d 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -72,7 +72,7 @@ func (self *SQLStorage) CreateTablesFromScript(scriptPath string) error { } // Return a list with all TPids defined in the system, even if incomplete, isolated in some table. -func (self *SQLStorage) GetTPIds() ([]string, error) { +func (self *SQLStorage) GetTpIds() ([]string, error) { rows, err := self.Db.Query( fmt.Sprintf("(SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s) UNION (SELECT tpid FROM %s)", utils.TBL_TP_TIMINGS, @@ -103,7 +103,7 @@ func (self *SQLStorage) GetTPIds() ([]string, error) { } // ToDo: TEST -func (self *SQLStorage) GetTPTableIds(tpid, table string, distinct utils.TPDistinctIds, filters map[string]string, pagination *utils.Paginator) ([]string, error) { +func (self *SQLStorage) GetTpTableIds(tpid, table string, distinct utils.TPDistinctIds, filters map[string]string, pagination *utils.Paginator) ([]string, error) { qry := fmt.Sprintf("SELECT DISTINCT %s FROM %s where tpid='%s'", distinct, table, tpid) for key, value := range filters { @@ -160,11 +160,11 @@ func (self *SQLStorage) GetTPTableIds(tpid, table string, distinct utils.TPDisti return ids, nil } -func (self *SQLStorage) SetTPTiming(tm *utils.ApierTPTiming) error { +func (self *SQLStorage) SetTpTiming(tm *utils.ApierTPTiming) error { return errors.New(utils.ERR_NOT_IMPLEMENTED) } -func (self *SQLStorage) RemTPData(table, tpid string, args ...string) error { +func (self *SQLStorage) RemTpData(table, tpid string, args ...string) error { tx := self.db.Begin() if len(table) == 0 { // Remove tpid out of all tables for _, tblName := range []string{utils.TBL_TP_TIMINGS, utils.TBL_TP_DESTINATIONS, utils.TBL_TP_RATES, utils.TBL_TP_DESTINATION_RATES, utils.TBL_TP_RATING_PLANS, utils.TBL_TP_RATE_PROFILES, @@ -197,7 +197,7 @@ func (self *SQLStorage) RemTPData(table, tpid string, args ...string) error { return nil } -func (self *SQLStorage) SetTPDestination(tpid string, dest *Destination) error { +func (self *SQLStorage) SetTpDestination(tpid string, dest *Destination) error { if len(dest.Prefixes) == 0 { return nil } @@ -222,7 +222,7 @@ func (self *SQLStorage) SetTPDestination(tpid string, dest *Destination) error { return nil } -func (self *SQLStorage) SetTPRates(tpid string, rts map[string][]*utils.RateSlot) error { +func (self *SQLStorage) SetTpRates(tpid string, rts map[string][]*utils.RateSlot) error { if len(rts) == 0 { return nil //Nothing to set } @@ -254,7 +254,7 @@ func (self *SQLStorage) SetTPRates(tpid string, rts map[string][]*utils.RateSlot return nil } -func (self *SQLStorage) SetTPDestinationRates(tpid string, drs map[string][]*utils.DestinationRate) error { +func (self *SQLStorage) SetTpDestinationRates(tpid string, drs map[string][]*utils.DestinationRate) error { if len(drs) == 0 { return nil //Nothing to set } @@ -285,7 +285,7 @@ func (self *SQLStorage) SetTPDestinationRates(tpid string, drs map[string][]*uti return nil } -func (self *SQLStorage) SetTPRatingPlans(tpid string, drts map[string][]*utils.TPRatingPlanBinding) error { +func (self *SQLStorage) SetTpRatingPlans(tpid string, drts map[string][]*utils.TPRatingPlanBinding) error { if len(drts) == 0 { return nil //Nothing to set } @@ -314,7 +314,7 @@ func (self *SQLStorage) SetTPRatingPlans(tpid string, drts map[string][]*utils.T return nil } -func (self *SQLStorage) SetTPRatingProfiles(tpid string, rpfs map[string]*utils.TPRatingProfile) error { +func (self *SQLStorage) SetTpRatingProfiles(tpid string, rpfs map[string]*utils.TPRatingProfile) error { if len(rpfs) == 0 { return nil //Nothing to set } @@ -348,7 +348,7 @@ func (self *SQLStorage) SetTPRatingProfiles(tpid string, rpfs map[string]*utils. return nil } -func (self *SQLStorage) SetTPSharedGroups(tpid string, sgs map[string][]*utils.TPSharedGroup) error { +func (self *SQLStorage) SetTpSharedGroups(tpid string, sgs map[string][]*utils.TPSharedGroup) error { if len(sgs) == 0 { return nil //Nothing to set } @@ -377,7 +377,7 @@ func (self *SQLStorage) SetTPSharedGroups(tpid string, sgs map[string][]*utils.T return nil } -func (self *SQLStorage) SetTPCdrStats(tpid string, css map[string][]*utils.TPCdrStat) error { +func (self *SQLStorage) SetTpCdrStats(tpid string, css map[string][]*utils.TPCdrStat) error { if len(css) == 0 { return nil //Nothing to set } @@ -426,7 +426,7 @@ func (self *SQLStorage) SetTPCdrStats(tpid string, css map[string][]*utils.TPCdr return nil } -func (self *SQLStorage) SetTPDerivedChargers(tpid string, sgs map[string][]*utils.TPDerivedCharger) error { +func (self *SQLStorage) SetTpDerivedChargers(tpid string, sgs map[string][]*utils.TPDerivedCharger) error { if len(sgs) == 0 { return nil //Nothing to set } @@ -473,7 +473,7 @@ func (self *SQLStorage) SetTPDerivedChargers(tpid string, sgs map[string][]*util return nil } -func (self *SQLStorage) SetTPLCRs(tpid string, lcrs map[string]*LCR) error { +func (self *SQLStorage) SetTpLCRs(tpid string, lcrs map[string]*LCR) error { if len(lcrs) == 0 { return nil //Nothing to set } @@ -498,7 +498,7 @@ func (self *SQLStorage) SetTPLCRs(tpid string, lcrs map[string]*LCR) error { return nil } -func (self *SQLStorage) SetTPActions(tpid string, acts map[string][]*utils.TPAction) error { +func (self *SQLStorage) SetTpActions(tpid string, acts map[string][]*utils.TPAction) error { if len(acts) == 0 { return nil //Nothing to set } @@ -539,7 +539,7 @@ func (self *SQLStorage) SetTPActions(tpid string, acts map[string][]*utils.TPAct return nil } -func (self *SQLStorage) GetTPActions(tpid, actsId string) (*utils.TPActions, error) { +func (self *SQLStorage) GetTpActions(tpid, actsId string) (*utils.TPActions, error) { acts := &utils.TPActions{TPid: tpid, ActionsId: actsId} var tpActions []*TpAction if err := self.db.Where(&TpAction{Tpid: tpid, Tag: actsId}).Find(&tpActions).Error; err != nil { @@ -565,7 +565,7 @@ func (self *SQLStorage) GetTPActions(tpid, actsId string) (*utils.TPActions, err } // Sets actionTimings in sqlDB. Imput is expected in form map[actionTimingId][]rows, eg a full .csv file content -func (self *SQLStorage) SetTPActionTimings(tpid string, ats map[string][]*utils.TPActionTiming) error { +func (self *SQLStorage) SetTpActionTimings(tpid string, ats map[string][]*utils.TPActionTiming) error { if len(ats) == 0 { return nil //Nothing to set } @@ -606,7 +606,7 @@ func (self *SQLStorage) GetTPActionTimings(tpid, tag string) (map[string][]*util return ats, nil } -func (self *SQLStorage) SetTPActionTriggers(tpid string, ats map[string][]*utils.TPActionTrigger) error { +func (self *SQLStorage) SetTpActionTriggers(tpid string, ats map[string][]*utils.TPActionTrigger) error { if len(ats) == 0 { return nil //Nothing to set } @@ -655,7 +655,7 @@ func (self *SQLStorage) SetTPActionTriggers(tpid string, ats map[string][]*utils } // Sets a group of account actions. Map key has the role of grouping within a tpid -func (self *SQLStorage) SetTPAccountActions(tpid string, aas map[string]*utils.TPAccountActions) error { +func (self *SQLStorage) SetTpAccountActions(tpid string, aas map[string]*utils.TPAccountActions) error { if len(aas) == 0 { return nil //Nothing to set } @@ -1212,9 +1212,8 @@ func (self *SQLStorage) GetTpRates(tpid, tag string) ([]*TpRate, error) { return tpRates, nil } -func (self *SQLStorage) GetTpDestinationRates(tpid, tag string, pagination *utils.Paginator) (map[string]*utils.TPDestinationRate, error) { - rts := make(map[string]*utils.TPDestinationRate) - var tpDestinationRates []TpDestinationRate +func (self *SQLStorage) GetTpDestinationRates(tpid, tag string, pagination *utils.Paginator) ([]*TpDestinationRate, error) { + var tpDestinationRates []*TpDestinationRate q := self.db.Where("tpid = ?", tpid) if len(tag) != 0 { q = q.Where("tag = ?", tag) @@ -1231,31 +1230,7 @@ func (self *SQLStorage) GetTpDestinationRates(tpid, tag string, pagination *util return nil, err } - for _, tpDr := range tpDestinationRates { - dr := &utils.TPDestinationRate{ - TPid: tpid, - DestinationRateId: tpDr.Tag, - DestinationRates: []*utils.DestinationRate{ - &utils.DestinationRate{ - DestinationId: tpDr.DestinationsTag, - RateId: tpDr.RatesTag, - RoundingMethod: tpDr.RoundingMethod, - RoundingDecimals: tpDr.RoundingDecimals, - MaxCost: tpDr.MaxCost, - MaxCostStrategy: tpDr.MaxCostStrategy, - }, - }, - } - existingDR, exists := rts[tpDr.Tag] - if exists { - existingDR.DestinationRates = append(existingDR.DestinationRates, dr.DestinationRates[0]) - } else { - existingDR = dr - } - rts[tpDr.Tag] = existingDR - - } - return rts, nil + return tpDestinationRates, nil } func (self *SQLStorage) GetTpTimings(tpid, tag string) ([]*TpTiming, error) { @@ -1270,10 +1245,8 @@ func (self *SQLStorage) GetTpTimings(tpid, tag string) ([]*TpTiming, error) { return tpTimings, nil } -func (self *SQLStorage) GetTpRatingPlans(tpid, tag string, pagination *utils.Paginator) (map[string][]*utils.TPRatingPlanBinding, error) { - rpbns := make(map[string][]*utils.TPRatingPlanBinding) - - var tpRatingPlans []TpRatingPlan +func (self *SQLStorage) GetTpRatingPlans(tpid, tag string, pagination *utils.Paginator) ([]*TpRatingPlan, error) { + var tpRatingPlans []*TpRatingPlan q := self.db.Where("tpid = ?", tpid) if len(tag) != 0 { q = q.Where("tag = ?", tag) @@ -1290,25 +1263,11 @@ func (self *SQLStorage) GetTpRatingPlans(tpid, tag string, pagination *utils.Pag } } - for _, tpRp := range tpRatingPlans { - rpb := &utils.TPRatingPlanBinding{ - DestinationRatesId: tpRp.DestratesTag, - TimingId: tpRp.TimingTag, - Weight: tpRp.Weight, - } - if _, exists := rpbns[tpRp.Tag]; exists { - rpbns[tpRp.Tag] = append(rpbns[tpRp.Tag], rpb) - } else { // New - rpbns[tpRp.Tag] = []*utils.TPRatingPlanBinding{rpb} - } - } - return rpbns, nil + return tpRatingPlans, nil } -func (self *SQLStorage) GetTpRatingProfiles(qryRpf *utils.TPRatingProfile) (map[string]*utils.TPRatingProfile, error) { - - rpfs := make(map[string]*utils.TPRatingProfile) - var tpRpfs []TpRatingProfile +func (self *SQLStorage) GetTpRatingProfiles(qryRpf *utils.TPRatingProfile) ([]*TpRatingProfile, error) { + var tpRpfs []*TpRatingProfile q := self.db.Where("tpid = ?", qryRpf.TPid) if len(qryRpf.Direction) != 0 { q = q.Where("direction = ?", qryRpf.Direction) @@ -1328,31 +1287,8 @@ func (self *SQLStorage) GetTpRatingProfiles(qryRpf *utils.TPRatingProfile) (map[ if err := q.Find(&tpRpfs).Error; err != nil { return nil, err } - for _, tpRpf := range tpRpfs { - rp := &utils.TPRatingProfile{ - TPid: tpRpf.Tpid, - LoadId: tpRpf.Loadid, - Direction: tpRpf.Direction, - Tenant: tpRpf.Tenant, - Category: tpRpf.Category, - Subject: tpRpf.Subject, - } - ra := &utils.TPRatingActivation{ - ActivationTime: tpRpf.ActivationTime, - RatingPlanId: tpRpf.RatingPlanTag, - FallbackSubjects: tpRpf.FallbackSubjects, - CdrStatQueueIds: tpRpf.CdrStatQueueIds, - } - if existingRpf, exists := rpfs[rp.KeyId()]; !exists { - rp.RatingPlanActivations = []*utils.TPRatingActivation{ra} - rpfs[rp.KeyId()] = rp - } else { // Exists, update - existingRpf.RatingPlanActivations = append(existingRpf.RatingPlanActivations, ra) - } - - } - return rpfs, nil + return tpRpfs, nil } func (self *SQLStorage) GetTpSharedGroups(tpid, tag string) (map[string][]*utils.TPSharedGroup, error) { diff --git a/engine/tp_data.go b/engine/tp_data.go deleted file mode 100644 index 68ea4f0fb..000000000 --- a/engine/tp_data.go +++ /dev/null @@ -1,392 +0,0 @@ -package engine - -import ( - "errors" - "log" - - "github.com/cgrates/cgrates/utils" -) - -type TPData struct { - actions map[string][]*Action - actionsTimings map[string][]*ActionTiming - actionsTriggers map[string][]*ActionTrigger - accountActions map[string]*Account - dirtyRpAliases []*TenantRatingSubject // used to clean aliases that might have changed - dirtyAccAliases []*TenantAccount // used to clean aliases that might have changed - destinations map[string]*Destination - rpAliases map[string]string - accAliases map[string]string - timings map[string]*utils.TPTiming - rates map[string]*utils.TPRate - destinationRates map[string]*utils.TPDestinationRate - ratingPlans map[string]*RatingPlan - ratingProfiles map[string]*RatingProfile - sharedGroups map[string]*SharedGroup - lcrs map[string]*LCR - derivedChargers map[string]utils.DerivedChargers - cdrStats map[string]*CdrStats -} - -func NewTPData() *TPData { - tp := &TPData{} - tp.actions = make(map[string][]*Action) - tp.actionsTimings = make(map[string][]*ActionTiming) - tp.actionsTriggers = make(map[string][]*ActionTrigger) - tp.rates = make(map[string]*utils.TPRate) - tp.destinations = make(map[string]*Destination) - tp.destinationRates = make(map[string]*utils.TPDestinationRate) - tp.timings = make(map[string]*utils.TPTiming) - tp.ratingPlans = make(map[string]*RatingPlan) - tp.ratingProfiles = make(map[string]*RatingProfile) - tp.sharedGroups = make(map[string]*SharedGroup) - tp.lcrs = make(map[string]*LCR) - tp.rpAliases = make(map[string]string) - tp.accAliases = make(map[string]string) - tp.timings = make(map[string]*utils.TPTiming) - tp.accountActions = make(map[string]*Account) - tp.destinations = make(map[string]*Destination) - tp.cdrStats = make(map[string]*CdrStats) - tp.derivedChargers = make(map[string]utils.DerivedChargers) - return tp -} - -func (tp *TPData) LoadDestinations(tps []*TpDestination) (err error) { - tp.destinations, err = TpDestinations(tps).GetDestinations() - return err -} - -func (tp *TPData) LoadTimings(tps []*TpTiming) (err error) { - tp.timings, err = TpTimings(tps).GetTimings() - return err -} - -func (tp *TPData) LoadRates(tps []*TpRate) (err error) { - tp.rates, err = TpRates(tps).GetRates() - return err -} - -func (tp *TPData) IsValid() bool { - valid := true - for rplTag, rpl := range tp.ratingPlans { - if !rpl.isContinous() { - log.Printf("The rating plan %s is not covering all weekdays", rplTag) - valid = false - } - if !rpl.areRatesSane() { - log.Printf("The rating plan %s contains invalid rate groups", rplTag) - valid = false - } - if !rpl.areTimingsSane() { - log.Printf("The rating plan %s contains invalid timings", rplTag) - valid = false - } - } - return valid -} - -func (tp *TPData) WriteToDatabase(dataStorage RatingStorage, accountingStorage AccountingStorage, flush, verbose bool) (err error) { - if dataStorage == nil { - return errors.New("No database connection!") - } - if flush { - dataStorage.Flush("") - } - if verbose { - log.Print("Destinations:") - } - for _, d := range tp.destinations { - err = dataStorage.SetDestination(d) - if err != nil { - return err - } - if verbose { - log.Print("\t", d.Id, " : ", d.Prefixes) - } - } - if verbose { - log.Print("Rating Plans:") - } - for _, rp := range tp.ratingPlans { - err = dataStorage.SetRatingPlan(rp) - if err != nil { - return err - } - if verbose { - log.Print("\t", rp.Id) - } - } - if verbose { - log.Print("Rating Profiles:") - } - for _, rp := range tp.ratingProfiles { - err = dataStorage.SetRatingProfile(rp) - if err != nil { - return err - } - if verbose { - log.Print("\t", rp.Id) - } - } - if verbose { - log.Print("Action Plans:") - } - for k, ats := range tp.actionsTimings { - err = accountingStorage.SetActionTimings(k, ats) - if err != nil { - return err - } - if verbose { - log.Println("\t", k) - } - } - if verbose { - log.Print("Shared Groups:") - } - for k, sg := range tp.sharedGroups { - err = accountingStorage.SetSharedGroup(sg) - if err != nil { - return err - } - if verbose { - log.Println("\t", k) - } - } - if verbose { - log.Print("LCR Rules:") - } - for k, lcr := range tp.lcrs { - err = dataStorage.SetLCR(lcr) - if err != nil { - return err - } - if verbose { - log.Println("\t", k) - } - } - if verbose { - log.Print("Actions:") - } - for k, as := range tp.actions { - err = accountingStorage.SetActions(k, as) - if err != nil { - return err - } - if verbose { - log.Println("\t", k) - } - } - if verbose { - log.Print("Account Actions:") - } - for _, ub := range tp.accountActions { - err = accountingStorage.SetAccount(ub) - if err != nil { - return err - } - if verbose { - log.Println("\t", ub.Id) - } - } - if verbose { - log.Print("Rating Profile Aliases:") - } - if err := dataStorage.RemoveRpAliases(tp.dirtyRpAliases); err != nil { - return err - } - for key, alias := range tp.rpAliases { - err = dataStorage.SetRpAlias(key, alias) - if err != nil { - return err - } - if verbose { - log.Print("\t", key) - } - } - if verbose { - log.Print("Account Aliases:") - } - if err := accountingStorage.RemoveAccAliases(tp.dirtyAccAliases); err != nil { - return err - } - for key, alias := range tp.accAliases { - err = accountingStorage.SetAccAlias(key, alias) - if err != nil { - return err - } - if verbose { - log.Print("\t", key) - } - } - if verbose { - log.Print("Derived Chargers:") - } - for key, dcs := range tp.derivedChargers { - err = accountingStorage.SetDerivedChargers(key, dcs) - if err != nil { - return err - } - if verbose { - log.Print("\t", key) - } - } - if verbose { - log.Print("CDR Stats Queues:") - } - for _, sq := range tp.cdrStats { - err = dataStorage.SetCdrStats(sq) - if err != nil { - return err - } - if verbose { - log.Print("\t", sq.Id) - } - } - return -} - -func (tp *TPData) ShowStatistics() { - // destinations - destCount := len(tp.destinations) - log.Print("Destinations: ", destCount) - prefixDist := make(map[int]int, 50) - prefixCount := 0 - for _, d := range tp.destinations { - prefixDist[len(d.Prefixes)] += 1 - prefixCount += len(d.Prefixes) - } - log.Print("Avg Prefixes: ", prefixCount/destCount) - log.Print("Prefixes distribution:") - for k, v := range prefixDist { - log.Printf("%d: %d", k, v) - } - // rating plans - rplCount := len(tp.ratingPlans) - log.Print("Rating plans: ", rplCount) - destRatesDist := make(map[int]int, 50) - destRatesCount := 0 - for _, rpl := range tp.ratingPlans { - destRatesDist[len(rpl.DestinationRates)] += 1 - destRatesCount += len(rpl.DestinationRates) - } - log.Print("Avg Destination Rates: ", destRatesCount/rplCount) - log.Print("Destination Rates distribution:") - for k, v := range destRatesDist { - log.Printf("%d: %d", k, v) - } - // rating profiles - rpfCount := len(tp.ratingProfiles) - log.Print("Rating profiles: ", rpfCount) - activDist := make(map[int]int, 50) - activCount := 0 - for _, rpf := range tp.ratingProfiles { - activDist[len(rpf.RatingPlanActivations)] += 1 - activCount += len(rpf.RatingPlanActivations) - } - log.Print("Avg Activations: ", activCount/rpfCount) - log.Print("Activation distribution:") - for k, v := range activDist { - log.Printf("%d: %d", k, v) - } - // actions - log.Print("Actions: ", len(tp.actions)) - // action plans - log.Print("Action plans: ", len(tp.actionsTimings)) - // action trigers - log.Print("Action trigers: ", len(tp.actionsTriggers)) - // account actions - log.Print("Account actions: ", len(tp.accountActions)) - // derivedChargers - log.Print("Derived Chargers: ", len(tp.derivedChargers)) - // lcr rules - log.Print("LCR rules: ", len(tp.lcrs)) - // cdr stats - log.Print("CDR stats: ", len(tp.cdrStats)) -} - -// Returns the identities loaded for a specific category, useful for cache reloads -func (tp *TPData) GetLoadedIds(categ string) ([]string, error) { - switch categ { - case DESTINATION_PREFIX: - keys := make([]string, len(tp.destinations)) - i := 0 - for k := range tp.destinations { - keys[i] = k - i++ - } - return keys, nil - case RATING_PLAN_PREFIX: - keys := make([]string, len(tp.ratingPlans)) - i := 0 - for k := range tp.ratingPlans { - keys[i] = k - i++ - } - return keys, nil - case RATING_PROFILE_PREFIX: - keys := make([]string, len(tp.ratingProfiles)) - i := 0 - for k := range tp.ratingProfiles { - keys[i] = k - i++ - } - return keys, nil - case ACTION_PREFIX: // actionsTimings - keys := make([]string, len(tp.actions)) - i := 0 - for k := range tp.actions { - keys[i] = k - i++ - } - return keys, nil - case ACTION_TIMING_PREFIX: // actionsTimings - keys := make([]string, len(tp.actionsTimings)) - i := 0 - for k := range tp.actionsTimings { - keys[i] = k - i++ - } - return keys, nil - case RP_ALIAS_PREFIX: // aliases - keys := make([]string, len(tp.rpAliases)) - i := 0 - for k := range tp.rpAliases { - keys[i] = k - i++ - } - return keys, nil - case ACC_ALIAS_PREFIX: // aliases - keys := make([]string, len(tp.accAliases)) - i := 0 - for k := range tp.accAliases { - keys[i] = k - i++ - } - return keys, nil - case DERIVEDCHARGERS_PREFIX: // derived chargers - keys := make([]string, len(tp.derivedChargers)) - i := 0 - for k := range tp.derivedChargers { - keys[i] = k - i++ - } - return keys, nil - case CDR_STATS_PREFIX: // cdr stats - keys := make([]string, len(tp.cdrStats)) - i := 0 - for k := range tp.cdrStats { - keys[i] = k - i++ - } - return keys, nil - case SHARED_GROUP_PREFIX: - keys := make([]string, len(tp.sharedGroups)) - i := 0 - for k := range tp.sharedGroups { - keys[i] = k - i++ - } - return keys, nil - } - return nil, errors.New("Unsupported category") -} diff --git a/engine/tp_reader.go b/engine/tp_reader.go index 9b830d3ca..e973a1abf 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -1,11 +1,37 @@ package engine +import ( + "errors" + "fmt" + "log" + "strings" + + "github.com/cgrates/cgrates/utils" +) + type TpReader struct { tpid string ratingStorage RatingStorage accountingStorage AccountingStorage lr LoadReader - tp *TPData + actions map[string][]*Action + actionsTimings map[string][]*ActionTiming + actionsTriggers map[string][]*ActionTrigger + accountActions map[string]*Account + dirtyRpAliases []*TenantRatingSubject // used to clean aliases that might have changed + dirtyAccAliases []*TenantAccount // used to clean aliases that might have changed + destinations map[string]*Destination + rpAliases map[string]string + accAliases map[string]string + timings map[string]*utils.TPTiming + rates map[string]*utils.TPRate + destinationRates map[string]*utils.TPDestinationRate + ratingPlans map[string]*RatingPlan + ratingProfiles map[string]*RatingProfile + sharedGroups map[string]*SharedGroup + lcrs map[string]*LCR + derivedChargers map[string]utils.DerivedChargers + cdrStats map[string]*CdrStats } func NewTpReader(rs RatingStorage, as AccountingStorage, lr LoadReader, tpid string) *TpReader { @@ -14,28 +40,32 @@ func NewTpReader(rs RatingStorage, as AccountingStorage, lr LoadReader, tpid str ratingStorage: rs, accountingStorage: as, lr: lr, - tp: NewTPData(), + actions: make(map[string][]*Action), + actionsTimings: make(map[string][]*ActionTiming), + actionsTriggers: make(map[string][]*ActionTrigger), + rates: make(map[string]*utils.TPRate), + destinations: make(map[string]*Destination), + destinationRates: make(map[string]*utils.TPDestinationRate), + timings: make(map[string]*utils.TPTiming), + ratingPlans: make(map[string]*RatingPlan), + ratingProfiles: make(map[string]*RatingProfile), + sharedGroups: make(map[string]*SharedGroup), + lcrs: make(map[string]*LCR), + rpAliases: make(map[string]string), + accAliases: make(map[string]string), + accountActions: make(map[string]*Account), + cdrStats: make(map[string]*CdrStats), + derivedChargers: make(map[string]utils.DerivedChargers), } } -func (tpr *TpReader) ShowStatistics() { - tpr.tp.ShowStatistics() -} - -func (tpr *TpReader) IsDataValid() bool { - return tpr.tp.IsValid() -} - -func (tpr *TpReader) WriteToDatabase(flush, verbose bool) (err error) { - return tpr.tp.WriteToDatabase(tpr.ratingStorage, tpr.accountingStorage, flush, verbose) -} - func (tpr *TpReader) LoadDestinations() (err error) { - tpDests, err := tpr.lr.GetTpDestinations(tpr.tpid, "") + tps, err := tpr.lr.GetTpDestinations(tpr.tpid, "") if err != nil { return err } - return tpr.tp.LoadDestinations(tpDests) + tpr.destinations, err = TpDestinations(tps).GetDestinations() + return err } func (tpr *TpReader) LoadTimings() (err error) { @@ -43,7 +73,9 @@ func (tpr *TpReader) LoadTimings() (err error) { if err != nil { return err } - return tpr.tp.LoadTimings(tps) + + tpr.timings, err = TpTimings(tps).GetTimings() + return err } func (tpr *TpReader) LoadRates() (err error) { @@ -51,7 +83,122 @@ func (tpr *TpReader) LoadRates() (err error) { if err != nil { return err } - return tpr.tp.LoadRates(tps) + tpr.rates, err = TpRates(tps).GetRates() + return err +} + +func (tpr *TpReader) LoadDestinationRates() (err error) { + tps, err := tpr.lr.GetTpDestinationRates(tpr.tpid, "", nil) + if err != nil { + return err + } + tpr.destinationRates, err = TpDestinationRates(tps).GetDestinationRates() + if err != nil { + return err + } + for _, drs := range tpr.destinationRates { + for _, dr := range drs.DestinationRates { + rate, exists := tpr.rates[dr.RateId] + if !exists { + return fmt.Errorf("Could not find rate for tag %v", dr.RateId) + } + dr.Rate = rate + destinationExists := dr.DestinationId == utils.ANY + if !destinationExists { + _, destinationExists = tpr.destinations[dr.DestinationId] + } + if !destinationExists { + if dbExists, err := tpr.ratingStorage.HasData(DESTINATION_PREFIX, dr.DestinationId); err != nil { + return err + } else if !dbExists { + return fmt.Errorf("Could not get destination for tag %v", dr.DestinationId) + } + } + } + } + return nil +} + +func (tpr *TpReader) LoadRatingPlans() (err error) { + tps, err := tpr.lr.GetTpRatingPlans(tpr.tpid, "", nil) + if err != nil { + return err + } + bindings, err := TpRatingPlans(tps).GetRatingPlans() + + if err != nil { + return err + } + + for tag, rplBnds := range bindings { + for _, rplBnd := range rplBnds { + t, exists := tpr.timings[rplBnd.TimingId] + if !exists { + return fmt.Errorf("Could not get timing for tag %v", rplBnd.TimingId) + } + rplBnd.SetTiming(t) + drs, exists := tpr.destinationRates[rplBnd.DestinationRatesId] + if !exists { + return fmt.Errorf("Could not find destination rate for tag %v", rplBnd.DestinationRatesId) + } + plan, exists := tpr.ratingPlans[tag] + if !exists { + plan = &RatingPlan{Id: tag} + tpr.ratingPlans[plan.Id] = plan + } + for _, dr := range drs.DestinationRates { + plan.AddRateInterval(dr.DestinationId, GetRateInterval(rplBnd, dr)) + } + } + } + return nil +} + +func (tpr *TpReader) LoadRatingProfiles() (err error) { + tps, err := tpr.lr.GetTpRatingProfiles(nil) + if err != nil { + return err + } + mpTpRpfs, err := TpRatingProfiles(tps).GetRatingProfiles() + + if err != nil { + return err + } + for _, tpRpf := range mpTpRpfs { + // extract aliases from subject + aliases := strings.Split(tpRpf.Subject, ";") + tpr.dirtyRpAliases = append(tpr.dirtyRpAliases, &TenantRatingSubject{Tenant: tpRpf.Tenant, Subject: aliases[0]}) + if len(aliases) > 1 { + tpRpf.Subject = aliases[0] + for _, alias := range aliases[1:] { + tpr.rpAliases[utils.RatingSubjectAliasKey(tpRpf.Tenant, alias)] = tpRpf.Subject + } + } + rpf := &RatingProfile{Id: tpRpf.KeyId()} + for _, tpRa := range tpRpf.RatingPlanActivations { + at, err := utils.ParseDate(tpRa.ActivationTime) + if err != nil { + return fmt.Errorf("Cannot parse activation time from %v", tpRa.ActivationTime) + } + _, exists := tpr.ratingPlans[tpRa.RatingPlanId] + if !exists { + if dbExists, err := tpr.ratingStorage.HasData(RATING_PLAN_PREFIX, tpRa.RatingPlanId); err != nil { + return err + } else if !dbExists { + return fmt.Errorf("Could not load rating plans for tag: %v", tpRa.RatingPlanId) + } + } + rpf.RatingPlanActivations = append(rpf.RatingPlanActivations, + &RatingPlanActivation{ + ActivationTime: at, + RatingPlanId: tpRa.RatingPlanId, + FallbackKeys: utils.FallbackSubjKeys(tpRpf.Direction, tpRpf.Tenant, tpRpf.Category, tpRa.FallbackSubjects), + CdrStatQueueIds: strings.Split(tpRa.CdrStatQueueIds, utils.INFIELD_SEP), + }) + } + tpr.ratingProfiles[tpRpf.KeyId()] = rpf + } + return nil } func (tpr *TpReader) LoadAll() error { @@ -100,3 +247,328 @@ func (tpr *TpReader) LoadAll() error { } return nil } + +func (tpr *TpReader) IsValid() bool { + valid := true + for rplTag, rpl := range tpr.ratingPlans { + if !rpl.isContinous() { + log.Printf("The rating plan %s is not covering all weekdays", rplTag) + valid = false + } + if !rpl.areRatesSane() { + log.Printf("The rating plan %s contains invalid rate groups", rplTag) + valid = false + } + if !rpl.areTimingsSane() { + log.Printf("The rating plan %s contains invalid timings", rplTag) + valid = false + } + } + return valid +} + +func (tpr *TpReader) WriteToDatabase(dataStorage RatingStorage, accountingStorage AccountingStorage, flush, verbose bool) (err error) { + if dataStorage == nil { + return errors.New("No database connection!") + } + if flush { + dataStorage.Flush("") + } + if verbose { + log.Print("Destinations:") + } + for _, d := range tpr.destinations { + err = dataStorage.SetDestination(d) + if err != nil { + return err + } + if verbose { + log.Print("\t", d.Id, " : ", d.Prefixes) + } + } + if verbose { + log.Print("Rating Plans:") + } + for _, rp := range tpr.ratingPlans { + err = dataStorage.SetRatingPlan(rp) + if err != nil { + return err + } + if verbose { + log.Print("\t", rp.Id) + } + } + if verbose { + log.Print("Rating Profiles:") + } + for _, rp := range tpr.ratingProfiles { + err = dataStorage.SetRatingProfile(rp) + if err != nil { + return err + } + if verbose { + log.Print("\t", rp.Id) + } + } + if verbose { + log.Print("Action Plans:") + } + for k, ats := range tpr.actionsTimings { + err = accountingStorage.SetActionTimings(k, ats) + if err != nil { + return err + } + if verbose { + log.Println("\t", k) + } + } + if verbose { + log.Print("Shared Groups:") + } + for k, sg := range tpr.sharedGroups { + err = accountingStorage.SetSharedGroup(sg) + if err != nil { + return err + } + if verbose { + log.Println("\t", k) + } + } + if verbose { + log.Print("LCR Rules:") + } + for k, lcr := range tpr.lcrs { + err = dataStorage.SetLCR(lcr) + if err != nil { + return err + } + if verbose { + log.Println("\t", k) + } + } + if verbose { + log.Print("Actions:") + } + for k, as := range tpr.actions { + err = accountingStorage.SetActions(k, as) + if err != nil { + return err + } + if verbose { + log.Println("\t", k) + } + } + if verbose { + log.Print("Account Actions:") + } + for _, ub := range tpr.accountActions { + err = accountingStorage.SetAccount(ub) + if err != nil { + return err + } + if verbose { + log.Println("\t", ub.Id) + } + } + if verbose { + log.Print("Rating Profile Aliases:") + } + if err := dataStorage.RemoveRpAliases(tpr.dirtyRpAliases); err != nil { + return err + } + for key, alias := range tpr.rpAliases { + err = dataStorage.SetRpAlias(key, alias) + if err != nil { + return err + } + if verbose { + log.Print("\t", key) + } + } + if verbose { + log.Print("Account Aliases:") + } + if err := accountingStorage.RemoveAccAliases(tpr.dirtyAccAliases); err != nil { + return err + } + for key, alias := range tpr.accAliases { + err = accountingStorage.SetAccAlias(key, alias) + if err != nil { + return err + } + if verbose { + log.Print("\t", key) + } + } + if verbose { + log.Print("Derived Chargers:") + } + for key, dcs := range tpr.derivedChargers { + err = accountingStorage.SetDerivedChargers(key, dcs) + if err != nil { + return err + } + if verbose { + log.Print("\t", key) + } + } + if verbose { + log.Print("CDR Stats Queues:") + } + for _, sq := range tpr.cdrStats { + err = dataStorage.SetCdrStats(sq) + if err != nil { + return err + } + if verbose { + log.Print("\t", sq.Id) + } + } + return +} + +func (tpr *TpReader) ShowStatistics() { + // destinations + destCount := len(tpr.destinations) + log.Print("Destinations: ", destCount) + prefixDist := make(map[int]int, 50) + prefixCount := 0 + for _, d := range tpr.destinations { + prefixDist[len(d.Prefixes)] += 1 + prefixCount += len(d.Prefixes) + } + log.Print("Avg Prefixes: ", prefixCount/destCount) + log.Print("Prefixes distribution:") + for k, v := range prefixDist { + log.Printf("%d: %d", k, v) + } + // rating plans + rplCount := len(tpr.ratingPlans) + log.Print("Rating plans: ", rplCount) + destRatesDist := make(map[int]int, 50) + destRatesCount := 0 + for _, rpl := range tpr.ratingPlans { + destRatesDist[len(rpl.DestinationRates)] += 1 + destRatesCount += len(rpl.DestinationRates) + } + log.Print("Avg Destination Rates: ", destRatesCount/rplCount) + log.Print("Destination Rates distribution:") + for k, v := range destRatesDist { + log.Printf("%d: %d", k, v) + } + // rating profiles + rpfCount := len(tpr.ratingProfiles) + log.Print("Rating profiles: ", rpfCount) + activDist := make(map[int]int, 50) + activCount := 0 + for _, rpf := range tpr.ratingProfiles { + activDist[len(rpf.RatingPlanActivations)] += 1 + activCount += len(rpf.RatingPlanActivations) + } + log.Print("Avg Activations: ", activCount/rpfCount) + log.Print("Activation distribution:") + for k, v := range activDist { + log.Printf("%d: %d", k, v) + } + // actions + log.Print("Actions: ", len(tpr.actions)) + // action plans + log.Print("Action plans: ", len(tpr.actionsTimings)) + // action trigers + log.Print("Action trigers: ", len(tpr.actionsTriggers)) + // account actions + log.Print("Account actions: ", len(tpr.accountActions)) + // derivedChargers + log.Print("Derived Chargers: ", len(tpr.derivedChargers)) + // lcr rules + log.Print("LCR rules: ", len(tpr.lcrs)) + // cdr stats + log.Print("CDR stats: ", len(tpr.cdrStats)) +} + +// Returns the identities loaded for a specific category, useful for cache reloads +func (tpr *TpReader) GetLoadedIds(categ string) ([]string, error) { + switch categ { + case DESTINATION_PREFIX: + keys := make([]string, len(tpr.destinations)) + i := 0 + for k := range tpr.destinations { + keys[i] = k + i++ + } + return keys, nil + case RATING_PLAN_PREFIX: + keys := make([]string, len(tpr.ratingPlans)) + i := 0 + for k := range tpr.ratingPlans { + keys[i] = k + i++ + } + return keys, nil + case RATING_PROFILE_PREFIX: + keys := make([]string, len(tpr.ratingProfiles)) + i := 0 + for k := range tpr.ratingProfiles { + keys[i] = k + i++ + } + return keys, nil + case ACTION_PREFIX: // actionsTimings + keys := make([]string, len(tpr.actions)) + i := 0 + for k := range tpr.actions { + keys[i] = k + i++ + } + return keys, nil + case ACTION_TIMING_PREFIX: // actionsTimings + keys := make([]string, len(tpr.actionsTimings)) + i := 0 + for k := range tpr.actionsTimings { + keys[i] = k + i++ + } + return keys, nil + case RP_ALIAS_PREFIX: // aliases + keys := make([]string, len(tpr.rpAliases)) + i := 0 + for k := range tpr.rpAliases { + keys[i] = k + i++ + } + return keys, nil + case ACC_ALIAS_PREFIX: // aliases + keys := make([]string, len(tpr.accAliases)) + i := 0 + for k := range tpr.accAliases { + keys[i] = k + i++ + } + return keys, nil + case DERIVEDCHARGERS_PREFIX: // derived chargers + keys := make([]string, len(tpr.derivedChargers)) + i := 0 + for k := range tpr.derivedChargers { + keys[i] = k + i++ + } + return keys, nil + case CDR_STATS_PREFIX: // cdr stats + keys := make([]string, len(tpr.cdrStats)) + i := 0 + for k := range tpr.cdrStats { + keys[i] = k + i++ + } + return keys, nil + case SHARED_GROUP_PREFIX: + keys := make([]string, len(tpr.sharedGroups)) + i := 0 + for k := range tpr.sharedGroups { + keys[i] = k + i++ + } + return keys, nil + } + return nil, errors.New("Unsupported category") +} diff --git a/utils/consts.go b/utils/consts.go index 2aa4571e6..b2909c0f9 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -60,20 +60,6 @@ const ( ACCOUNT_ACTIONS_CSV = "AccountActions.csv" DERIVED_CHARGERS_CSV = "DerivedChargers.csv" CDR_STATS_CSV = "CdrStats.csv" - TIMINGS_NRCOLS = 6 - DESTINATIONS_NRCOLS = 2 - RATES_NRCOLS = 6 - DESTINATION_RATES_NRCOLS = 7 - DESTRATE_TIMINGS_NRCOLS = 4 - RATE_PROFILES_NRCOLS = 8 - SHARED_GROUPS_NRCOLS = 4 - LCRS_NRCOLS = 11 - ACTIONS_NRCOLS = 15 - ACTION_PLANS_NRCOLS = 4 - ACTION_TRIGGERS_NRCOLS = 19 - ACCOUNT_ACTIONS_NRCOLS = 5 - DERIVED_CHARGERS_NRCOLS = 19 - CDR_STATS_NRCOLS = 23 ROUNDING_UP = "*up" ROUNDING_MIDDLE = "*middle" ROUNDING_DOWN = "*down"