/* Rating system designed to be used in VoIP Carriers World Copyright (C) 2012-2015 ITsysCOM This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ package engine import ( "sort" "strconv" "strings" "time" "github.com/cgrates/cgrates/cache2go" "github.com/cgrates/cgrates/utils" ) const ( LCR_STRATEGY_STATIC = "*static" LCR_STRATEGY_LOWEST = "*lowest_cost" LCR_STRATEGY_HIGHEST = "*highest_cost" LCR_STRATEGY_QOS_WITH_THRESHOLD = "*qos_with_threshold" LCR_STRATEGY_QOS = "*qos" ) type LCR struct { Tenant string Category string Direction string Account string Subject string Activations []*LCRActivation } type LCRActivation struct { ActivationTime time.Time Entries []*LCREntry } type LCREntry struct { DestinationId string RPCategory string Strategy string StrategyParams string Weight float64 precision int } type LCRCost []*LCRTimeSpan type LCRTimeSpan struct { StartTime time.Time SupplierCosts []*LCRSupplierCost Entry *LCREntry } type LCRSupplierCost struct { Supplier string Cost float64 Error error QOS map[string]float64 qosSortParams []string } func (lcr *LCR) GetId() string { return utils.ConcatenatedKey(lcr.Direction, lcr.Tenant, lcr.Category, lcr.Account, lcr.Subject) } func (lcr *LCR) Len() int { return len(lcr.Activations) } func (lcr *LCR) Swap(i, j int) { lcr.Activations[i], lcr.Activations[j] = lcr.Activations[j], lcr.Activations[i] } func (lcr *LCR) Less(i, j int) bool { return lcr.Activations[i].ActivationTime.Before(lcr.Activations[j].ActivationTime) } func (lcr *LCR) Sort() { sort.Sort(lcr) } func (le *LCREntry) GetSuppliers() []string { suppliers := strings.Split(le.StrategyParams, utils.INFIELD_SEP) for i := 0; i < len(suppliers); i++ { suppliers[i] = strings.TrimSpace(suppliers[i]) } return suppliers } func (le *LCREntry) GetQOSLimits() (minASR, maxASR float64, minACD, maxACD time.Duration) { // MIN_ASR;MAX_ASR;MIN_ACD;MAX_ACD params := strings.Split(le.StrategyParams, utils.INFIELD_SEP) if len(params) == 4 { var err error if minASR, err = strconv.ParseFloat(params[0], 64); err != nil { minASR = -1 } if maxASR, err = strconv.ParseFloat(params[1], 64); err != nil { maxASR = -1 } if minACD, err = time.ParseDuration(params[2]); err != nil { minACD = -1 } if maxACD, err = time.ParseDuration(params[3]); err != nil { maxACD = -1 } } return } func (le *LCREntry) GetQOSSortParams() []string { // ASR;ACD if params := strings.Split(le.StrategyParams, utils.INFIELD_SEP); len(params) > 0 { return params } return []string{ASR, ACD} } type LCREntriesSorter []*LCREntry func (es LCREntriesSorter) Len() int { return len(es) } func (es LCREntriesSorter) Swap(i, j int) { es[i], es[j] = es[j], es[i] } func (es LCREntriesSorter) Less(j, i int) bool { return es[i].precision < es[j].precision || (es[i].precision == es[j].precision && es[i].Weight < es[j].Weight) } func (es LCREntriesSorter) Sort() { sort.Sort(es) } func (lcra *LCRActivation) GetLCREntryForPrefix(destination string) *LCREntry { var potentials LCREntriesSorter for _, p := range utils.SplitPrefix(destination, MIN_PREFIX_MATCH) { if x, err := cache2go.GetCached(DESTINATION_PREFIX + p); err == nil { destIds := x.([]string) for _, dId := range destIds { for _, entry := range lcra.Entries { if entry.DestinationId == dId { entry.precision = len(p) potentials = append(potentials, entry) } } } } } if len(potentials) > 0 { // sort by precision and weight potentials.Sort() return potentials[0] } // return the *any entry if it exists for _, entry := range lcra.Entries { if entry.DestinationId == utils.ANY { return entry } } return nil } func (lts *LCRTimeSpan) Sort() { switch lts.Entry.Strategy { case LCR_STRATEGY_LOWEST: sort.Sort(LowestSupplierCostSorter(lts.SupplierCosts)) case LCR_STRATEGY_HIGHEST: sort.Sort(HighestSupplierCostSorter(lts.SupplierCosts)) case LCR_STRATEGY_QOS: sort.Sort(QOSSorter(lts.SupplierCosts)) } } type LowestSupplierCostSorter []*LCRSupplierCost func (lscs LowestSupplierCostSorter) Len() int { return len(lscs) } func (lscs LowestSupplierCostSorter) Swap(i, j int) { lscs[i], lscs[j] = lscs[j], lscs[i] } func (lscs LowestSupplierCostSorter) Less(i, j int) bool { return lscs[i].Cost < lscs[j].Cost } type HighestSupplierCostSorter []*LCRSupplierCost func (hscs HighestSupplierCostSorter) Len() int { return len(hscs) } func (hscs HighestSupplierCostSorter) Swap(i, j int) { hscs[i], hscs[j] = hscs[j], hscs[i] } func (hscs HighestSupplierCostSorter) Less(i, j int) bool { return hscs[i].Cost > hscs[j].Cost } type QOSSorter []*LCRSupplierCost func (qoss QOSSorter) Len() int { return len(qoss) } func (qoss QOSSorter) Swap(i, j int) { qoss[i], qoss[j] = qoss[j], qoss[i] } func (qoss QOSSorter) Less(i, j int) bool { for _, param := range qoss[i].qosSortParams { if qoss[i].QOS[param] < qoss[j].QOS[param] { return true } if qoss[i].QOS[param] == qoss[j].QOS[param] { continue } } return false }