Renaming from SupplierS -> RouteS ( part 1)

This commit is contained in:
TeoV
2020-04-27 18:03:05 +03:00
committed by Dan Christian Bogos
parent 1127fe3177
commit cdaa675234
16 changed files with 423 additions and 424 deletions

223
engine/libroutes.go Normal file
View File

@@ -0,0 +1,223 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package engine
import (
"fmt"
"sort"
"strings"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
// SortedRoute represents one route in SortedRoutes
type SortedRoute struct {
RouteID string
RouteParameters string
SortingData map[string]interface{} // store here extra info like cost or stats
}
// SortedRoutes is returned as part of GetRoutes call
type SortedRoutes struct {
ProfileID string // Profile matched
Sorting string // Sorting algorithm
Count int // number of suppliers returned
SortedRoutes []*SortedRoute // list of supplier IDs and SortingData data
}
// RouteIDs returns a list of route IDs
func (sRoutes *SortedRoutes) RouteIDs() (rIDs []string) {
rIDs = make([]string, len(sRoutes.SortedRoutes))
for i, sRoute := range sRoutes.SortedRoutes {
rIDs[i] = sRoute.RouteID
}
return
}
// RoutesWithParams returns a list of routes IDs with Parameters
func (sRoutes *SortedRoutes) RoutesWithParams() (sPs []string) {
sPs = make([]string, len(sRoutes.SortedRoutes))
for i, spl := range sRoutes.SortedRoutes {
sPs[i] = spl.RouteID
if spl.RouteParameters != "" {
sPs[i] += utils.InInFieldSep + spl.RouteParameters
}
}
return
}
// SortWeight is part of sort interface, sort based on Weight
func (sRoutes *SortedRoutes) SortWeight() {
sort.Slice(sRoutes.SortedRoutes, func(i, j int) bool {
return sRoutes.SortedRoutes[i].SortingData[utils.Weight].(float64) > sRoutes.SortedRoutes[j].SortingData[utils.Weight].(float64)
})
}
// SortLeastCost is part of sort interface,
// sort ascendent based on Cost with fallback on Weight
func (sSpls *SortedRoutes) SortLeastCost() {
sort.Slice(sSpls.SortedRoutes, func(i, j int) bool {
if sSpls.SortedRoutes[i].SortingData[utils.Cost].(float64) == sSpls.SortedRoutes[j].SortingData[utils.Cost].(float64) {
return sSpls.SortedRoutes[i].SortingData[utils.Weight].(float64) > sSpls.SortedRoutes[j].SortingData[utils.Weight].(float64)
}
return sSpls.SortedRoutes[i].SortingData[utils.Cost].(float64) < sSpls.SortedRoutes[j].SortingData[utils.Cost].(float64)
})
}
// SortHighestCost is part of sort interface,
// sort descendent based on Cost with fallback on Weight
func (sSpls *SortedRoutes) SortHighestCost() {
sort.Slice(sSpls.SortedRoutes, func(i, j int) bool {
if sSpls.SortedRoutes[i].SortingData[utils.Cost].(float64) == sSpls.SortedRoutes[j].SortingData[utils.Cost].(float64) {
return sSpls.SortedRoutes[i].SortingData[utils.Weight].(float64) > sSpls.SortedRoutes[j].SortingData[utils.Weight].(float64)
}
return sSpls.SortedRoutes[i].SortingData[utils.Cost].(float64) > sSpls.SortedRoutes[j].SortingData[utils.Cost].(float64)
})
}
// SortQOS is part of sort interface,
// sort based on Stats
func (sSpls *SortedRoutes) SortQOS(params []string) {
//sort suppliers
sort.Slice(sSpls.SortedRoutes, func(i, j int) bool {
for _, param := range params {
//in case we have the same value for the current param we skip to the next one
if sSpls.SortedRoutes[i].SortingData[param].(float64) == sSpls.SortedRoutes[j].SortingData[param].(float64) {
continue
}
switch param {
default:
if sSpls.SortedRoutes[i].SortingData[param].(float64) > sSpls.SortedRoutes[j].SortingData[param].(float64) {
return true
}
return false
case utils.MetaPDD: //in case of pdd the smallest value if the best
if sSpls.SortedRoutes[i].SortingData[param].(float64) < sSpls.SortedRoutes[j].SortingData[param].(float64) {
return true
}
return false
}
}
//in case that we have the same value for all params we sort base on weight
return sSpls.SortedRoutes[i].SortingData[utils.Weight].(float64) > sSpls.SortedRoutes[j].SortingData[utils.Weight].(float64)
})
}
// SortResourceAscendent is part of sort interface,
// sort ascendent based on ResourceUsage with fallback on Weight
func (sSpls *SortedRoutes) SortResourceAscendent() {
sort.Slice(sSpls.SortedRoutes, func(i, j int) bool {
if sSpls.SortedRoutes[i].SortingData[utils.ResourceUsage].(float64) == sSpls.SortedRoutes[j].SortingData[utils.ResourceUsage].(float64) {
return sSpls.SortedRoutes[i].SortingData[utils.Weight].(float64) > sSpls.SortedRoutes[j].SortingData[utils.Weight].(float64)
}
return sSpls.SortedRoutes[i].SortingData[utils.ResourceUsage].(float64) < sSpls.SortedRoutes[j].SortingData[utils.ResourceUsage].(float64)
})
}
// SortResourceDescendent is part of sort interface,
// sort descendent based on ResourceUsage with fallback on Weight
func (sSpls *SortedRoutes) SortResourceDescendent() {
sort.Slice(sSpls.SortedRoutes, func(i, j int) bool {
if sSpls.SortedRoutes[i].SortingData[utils.ResourceUsage].(float64) == sSpls.SortedRoutes[j].SortingData[utils.ResourceUsage].(float64) {
return sSpls.SortedRoutes[i].SortingData[utils.Weight].(float64) > sSpls.SortedRoutes[j].SortingData[utils.Weight].(float64)
}
return sSpls.SortedRoutes[i].SortingData[utils.ResourceUsage].(float64) > sSpls.SortedRoutes[j].SortingData[utils.ResourceUsage].(float64)
})
}
// SortLoadDistribution is part of sort interface,
// sort based on the following formula (float64(ratio + metricVal) / float64(ratio)) -1 with fallback on Weight
func (sSpls *SortedRoutes) SortLoadDistribution() {
sort.Slice(sSpls.SortedRoutes, func(i, j int) bool {
splIVal := ((sSpls.SortedRoutes[i].SortingData[utils.Ratio].(float64)+sSpls.SortedRoutes[i].SortingData[utils.Load].(float64))/sSpls.SortedRoutes[i].SortingData[utils.Ratio].(float64) - 1.0)
splJVal := ((sSpls.SortedRoutes[j].SortingData[utils.Ratio].(float64)+sSpls.SortedRoutes[j].SortingData[utils.Load].(float64))/sSpls.SortedRoutes[j].SortingData[utils.Ratio].(float64) - 1.0)
if splIVal == splJVal {
return sSpls.SortedRoutes[i].SortingData[utils.Weight].(float64) > sSpls.SortedRoutes[j].SortingData[utils.Weight].(float64)
}
return splIVal < splJVal
})
}
// Digest returns list of supplierIDs + parameters for easier outside access
// format suppl1:suppl1params,suppl2:suppl2params
func (sSpls *SortedRoutes) Digest() string {
return strings.Join(sSpls.RoutesWithParams(), utils.FIELDS_SEP)
}
func (sSpls *SortedRoutes) AsNavigableMap() (nm *config.NavigableMap) {
mp := map[string]interface{}{
"ProfileID": sSpls.ProfileID,
"Sorting": sSpls.Sorting,
"Count": sSpls.Count,
}
sm := make([]map[string]interface{}, len(sSpls.SortedRoutes))
for i, ss := range sSpls.SortedRoutes {
sm[i] = map[string]interface{}{
"SupplierID": ss.RouteID,
"SupplierParameters": ss.RouteParameters,
"SortingData": ss.SortingData,
}
}
mp["SortedSuppliers"] = sm
return config.NewNavigableMap(mp)
}
type SupplierWithParams struct {
SupplierName string
SupplierParams string
}
// SuppliersSorter is the interface which needs to be implemented by supplier sorters
type RoutesSorter interface {
SortRoutes(string, []*Route, *utils.CGREvent, *optsGetSuppliers) (*SortedRoutes, error)
}
// NewRouteSortDispatcher constructs RouteSortDispatcher
func NewRouteSortDispatcher(lcrS *RouteService) (rsd RouteSortDispatcher, err error) {
rsd = make(map[string]RoutesSorter)
rsd[utils.MetaWeight] = NewWeightSorter(lcrS)
rsd[utils.MetaLC] = NewLeastCostSorter(lcrS)
rsd[utils.MetaHC] = NewHighestCostSorter(lcrS)
rsd[utils.MetaQOS] = NewQOSSupplierSorter(lcrS)
rsd[utils.MetaReas] = NewResourceAscendetSorter(lcrS)
rsd[utils.MetaReds] = NewResourceDescendentSorter(lcrS)
rsd[utils.MetaLoad] = NewLoadDistributionSorter(lcrS)
return
}
// RouteSortDispatcher will initialize strategies
// and dispatch requests to them
type RouteSortDispatcher map[string]RoutesSorter
func (ssd RouteSortDispatcher) SortSuppliers(prflID, strategy string,
suppls []*Route, suplEv *utils.CGREvent, extraOpts *optsGetSuppliers) (sortedRoutes *SortedRoutes, err error) {
sd, has := ssd[strategy]
if !has {
return nil, fmt.Errorf("unsupported sorting strategy: %s", strategy)
}
if sortedRoutes, err = sd.SortRoutes(prflID, suppls, suplEv, extraOpts); err != nil {
return
}
if len(sortedRoutes.SortedRoutes) == 0 {
return nil, utils.ErrNotFound
}
return
}

View File

@@ -1,223 +0,0 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package engine
import (
"fmt"
"sort"
"strings"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
// SupplierReply represents one supplier in
type SortedSupplier struct {
SupplierID string
SupplierParameters string
SortingData map[string]interface{} // store here extra info like cost or stats
}
// SuppliersReply is returned as part of GetSuppliers call
type SortedSuppliers struct {
ProfileID string // Profile matched
Sorting string // Sorting algorithm
Count int // number of suppliers returned
SortedSuppliers []*SortedSupplier // list of supplier IDs and SortingData data
}
// SupplierIDs returns list of suppliers
func (sSpls *SortedSuppliers) SupplierIDs() (sIDs []string) {
sIDs = make([]string, len(sSpls.SortedSuppliers))
for i, spl := range sSpls.SortedSuppliers {
sIDs[i] = spl.SupplierID
}
return
}
// SupplierIDs returns list of suppliers
func (sSpls *SortedSuppliers) SuppliersWithParams() (sPs []string) {
sPs = make([]string, len(sSpls.SortedSuppliers))
for i, spl := range sSpls.SortedSuppliers {
sPs[i] = spl.SupplierID
if spl.SupplierParameters != "" {
sPs[i] += utils.InInFieldSep + spl.SupplierParameters
}
}
return
}
// SortWeight is part of sort interface, sort based on Weight
func (sSpls *SortedSuppliers) SortWeight() {
sort.Slice(sSpls.SortedSuppliers, func(i, j int) bool {
return sSpls.SortedSuppliers[i].SortingData[utils.Weight].(float64) > sSpls.SortedSuppliers[j].SortingData[utils.Weight].(float64)
})
}
// SortLeastCost is part of sort interface,
// sort ascendent based on Cost with fallback on Weight
func (sSpls *SortedSuppliers) SortLeastCost() {
sort.Slice(sSpls.SortedSuppliers, func(i, j int) bool {
if sSpls.SortedSuppliers[i].SortingData[utils.Cost].(float64) == sSpls.SortedSuppliers[j].SortingData[utils.Cost].(float64) {
return sSpls.SortedSuppliers[i].SortingData[utils.Weight].(float64) > sSpls.SortedSuppliers[j].SortingData[utils.Weight].(float64)
}
return sSpls.SortedSuppliers[i].SortingData[utils.Cost].(float64) < sSpls.SortedSuppliers[j].SortingData[utils.Cost].(float64)
})
}
// SortHighestCost is part of sort interface,
// sort descendent based on Cost with fallback on Weight
func (sSpls *SortedSuppliers) SortHighestCost() {
sort.Slice(sSpls.SortedSuppliers, func(i, j int) bool {
if sSpls.SortedSuppliers[i].SortingData[utils.Cost].(float64) == sSpls.SortedSuppliers[j].SortingData[utils.Cost].(float64) {
return sSpls.SortedSuppliers[i].SortingData[utils.Weight].(float64) > sSpls.SortedSuppliers[j].SortingData[utils.Weight].(float64)
}
return sSpls.SortedSuppliers[i].SortingData[utils.Cost].(float64) > sSpls.SortedSuppliers[j].SortingData[utils.Cost].(float64)
})
}
// SortQOS is part of sort interface,
// sort based on Stats
func (sSpls *SortedSuppliers) SortQOS(params []string) {
//sort suppliers
sort.Slice(sSpls.SortedSuppliers, func(i, j int) bool {
for _, param := range params {
//in case we have the same value for the current param we skip to the next one
if sSpls.SortedSuppliers[i].SortingData[param].(float64) == sSpls.SortedSuppliers[j].SortingData[param].(float64) {
continue
}
switch param {
default:
if sSpls.SortedSuppliers[i].SortingData[param].(float64) > sSpls.SortedSuppliers[j].SortingData[param].(float64) {
return true
}
return false
case utils.MetaPDD: //in case of pdd the smallest value if the best
if sSpls.SortedSuppliers[i].SortingData[param].(float64) < sSpls.SortedSuppliers[j].SortingData[param].(float64) {
return true
}
return false
}
}
//in case that we have the same value for all params we sort base on weight
return sSpls.SortedSuppliers[i].SortingData[utils.Weight].(float64) > sSpls.SortedSuppliers[j].SortingData[utils.Weight].(float64)
})
}
// SortResourceAscendent is part of sort interface,
// sort ascendent based on ResourceUsage with fallback on Weight
func (sSpls *SortedSuppliers) SortResourceAscendent() {
sort.Slice(sSpls.SortedSuppliers, func(i, j int) bool {
if sSpls.SortedSuppliers[i].SortingData[utils.ResourceUsage].(float64) == sSpls.SortedSuppliers[j].SortingData[utils.ResourceUsage].(float64) {
return sSpls.SortedSuppliers[i].SortingData[utils.Weight].(float64) > sSpls.SortedSuppliers[j].SortingData[utils.Weight].(float64)
}
return sSpls.SortedSuppliers[i].SortingData[utils.ResourceUsage].(float64) < sSpls.SortedSuppliers[j].SortingData[utils.ResourceUsage].(float64)
})
}
// SortResourceDescendent is part of sort interface,
// sort descendent based on ResourceUsage with fallback on Weight
func (sSpls *SortedSuppliers) SortResourceDescendent() {
sort.Slice(sSpls.SortedSuppliers, func(i, j int) bool {
if sSpls.SortedSuppliers[i].SortingData[utils.ResourceUsage].(float64) == sSpls.SortedSuppliers[j].SortingData[utils.ResourceUsage].(float64) {
return sSpls.SortedSuppliers[i].SortingData[utils.Weight].(float64) > sSpls.SortedSuppliers[j].SortingData[utils.Weight].(float64)
}
return sSpls.SortedSuppliers[i].SortingData[utils.ResourceUsage].(float64) > sSpls.SortedSuppliers[j].SortingData[utils.ResourceUsage].(float64)
})
}
// SortLoadDistribution is part of sort interface,
// sort based on the following formula (float64(ratio + metricVal) / float64(ratio)) -1 with fallback on Weight
func (sSpls *SortedSuppliers) SortLoadDistribution() {
sort.Slice(sSpls.SortedSuppliers, func(i, j int) bool {
splIVal := ((sSpls.SortedSuppliers[i].SortingData[utils.Ratio].(float64)+sSpls.SortedSuppliers[i].SortingData[utils.Load].(float64))/sSpls.SortedSuppliers[i].SortingData[utils.Ratio].(float64) - 1.0)
splJVal := ((sSpls.SortedSuppliers[j].SortingData[utils.Ratio].(float64)+sSpls.SortedSuppliers[j].SortingData[utils.Load].(float64))/sSpls.SortedSuppliers[j].SortingData[utils.Ratio].(float64) - 1.0)
if splIVal == splJVal {
return sSpls.SortedSuppliers[i].SortingData[utils.Weight].(float64) > sSpls.SortedSuppliers[j].SortingData[utils.Weight].(float64)
}
return splIVal < splJVal
})
}
// Digest returns list of supplierIDs + parameters for easier outside access
// format suppl1:suppl1params,suppl2:suppl2params
func (sSpls *SortedSuppliers) Digest() string {
return strings.Join(sSpls.SuppliersWithParams(), utils.FIELDS_SEP)
}
func (sSpls *SortedSuppliers) AsNavigableMap() (nm *config.NavigableMap) {
mp := map[string]interface{}{
"ProfileID": sSpls.ProfileID,
"Sorting": sSpls.Sorting,
"Count": sSpls.Count,
}
sm := make([]map[string]interface{}, len(sSpls.SortedSuppliers))
for i, ss := range sSpls.SortedSuppliers {
sm[i] = map[string]interface{}{
"SupplierID": ss.SupplierID,
"SupplierParameters": ss.SupplierParameters,
"SortingData": ss.SortingData,
}
}
mp["SortedSuppliers"] = sm
return config.NewNavigableMap(mp)
}
type SupplierWithParams struct {
SupplierName string
SupplierParams string
}
// SuppliersSorter is the interface which needs to be implemented by supplier sorters
type SuppliersSorter interface {
SortSuppliers(string, []*Supplier, *utils.CGREvent, *optsGetSuppliers) (*SortedSuppliers, error)
}
// NewSupplierSortDispatcher constructs SupplierSortDispatcher
func NewSupplierSortDispatcher(lcrS *SupplierService) (ssd SupplierSortDispatcher, err error) {
ssd = make(map[string]SuppliersSorter)
ssd[utils.MetaWeight] = NewWeightSorter(lcrS)
ssd[utils.MetaLC] = NewLeastCostSorter(lcrS)
ssd[utils.MetaHC] = NewHighestCostSorter(lcrS)
ssd[utils.MetaQOS] = NewQOSSupplierSorter(lcrS)
ssd[utils.MetaReas] = NewResourceAscendetSorter(lcrS)
ssd[utils.MetaReds] = NewResourceDescendentSorter(lcrS)
ssd[utils.MetaLoad] = NewLoadDistributionSorter(lcrS)
return
}
// SupplierStrategyHandler will initialize strategies
// and dispatch requests to them
type SupplierSortDispatcher map[string]SuppliersSorter
func (ssd SupplierSortDispatcher) SortSuppliers(prflID, strategy string,
suppls []*Supplier, suplEv *utils.CGREvent, extraOpts *optsGetSuppliers) (sortedSuppls *SortedSuppliers, err error) {
sd, has := ssd[strategy]
if !has {
return nil, fmt.Errorf("unsupported sorting strategy: %s", strategy)
}
if sortedSuppls, err = sd.SortSuppliers(prflID, suppls, suplEv, extraOpts); err != nil {
return
}
if len(sortedSuppls.SortedSuppliers) == 0 {
return nil, utils.ErrNotFound
}
return
}

View File

@@ -1893,28 +1893,28 @@ func FilterToTPFilter(f *Filter) (tpFltr *utils.TPFilterProfile) {
return
}
type TpSuppliers []*TpSupplier
type TPRoutes []*TpRoute
// CSVHeader return the header for csv fields as a slice of string
func (tps TpSuppliers) CSVHeader() (result []string) {
func (tps TPRoutes) CSVHeader() (result []string) {
return []string{"#" + utils.Tenant, utils.ID, utils.FilterIDs, utils.ActivationIntervalString,
utils.Sorting, utils.SortingParameters, utils.SupplierID, utils.SupplierFilterIDs,
utils.SupplierAccountIDs, utils.SupplierRatingplanIDs, utils.SupplierResourceIDs,
utils.SupplierStatIDs, utils.SupplierWeight, utils.SupplierBlocker,
utils.SupplierParameters, utils.Weight,
utils.Sorting, utils.SortingParameters, utils.RouteID, utils.RouteFilterIDs,
utils.RouteAccountIDs, utils.RouteRatingplanIDs, utils.RouteResourceIDs,
utils.RouteStatIDs, utils.RouteWeight, utils.RouteBlocker,
utils.RouteParameters, utils.Weight,
}
}
func (tps TpSuppliers) AsTPSuppliers() (result []*utils.TPSupplierProfile) {
func (tps TPRoutes) AsTPRouteProfile() (result []*utils.TPRouteProfile) {
filtermap := make(map[string]utils.StringMap)
mst := make(map[string]*utils.TPSupplierProfile)
suppliersMap := make(map[string]map[string]*utils.TPSupplier)
mst := make(map[string]*utils.TPRouteProfile)
suppliersMap := make(map[string]map[string]*utils.TPRoute)
sortingParameterMap := make(map[string]utils.StringMap)
for _, tp := range tps {
tenID := (&utils.TenantID{Tenant: tp.Tenant, ID: tp.ID}).TenantID()
th, found := mst[tenID]
if !found {
th = &utils.TPSupplierProfile{
th = &utils.TPRouteProfile{
TPid: tp.Tpid,
Tenant: tp.Tenant,
ID: tp.ID,
@@ -1922,42 +1922,42 @@ func (tps TpSuppliers) AsTPSuppliers() (result []*utils.TPSupplierProfile) {
SortingParameters: []string{},
}
}
if tp.SupplierID != "" {
if tp.RouteID != "" {
if _, has := suppliersMap[tenID]; !has {
suppliersMap[(&utils.TenantID{Tenant: tp.Tenant, ID: tp.ID}).TenantID()] = make(map[string]*utils.TPSupplier)
suppliersMap[(&utils.TenantID{Tenant: tp.Tenant, ID: tp.ID}).TenantID()] = make(map[string]*utils.TPRoute)
}
sup, found := suppliersMap[tenID][tp.SupplierID]
sup, found := suppliersMap[tenID][tp.RouteID]
if !found {
sup = &utils.TPSupplier{
ID: tp.SupplierID,
Weight: tp.SupplierWeight,
Blocker: tp.SupplierBlocker,
sup = &utils.TPRoute{
ID: tp.RouteID,
Weight: tp.RouteWeight,
Blocker: tp.RouteBlocker,
}
}
if tp.SupplierParameters != "" {
sup.SupplierParameters = tp.SupplierParameters
if tp.RouteParameters != "" {
sup.RouteParameters = tp.RouteParameters
}
if tp.SupplierFilterIDs != "" {
supFilterSplit := strings.Split(tp.SupplierFilterIDs, utils.INFIELD_SEP)
if tp.RouteFilterIDs != "" {
supFilterSplit := strings.Split(tp.RouteFilterIDs, utils.INFIELD_SEP)
sup.FilterIDs = append(sup.FilterIDs, supFilterSplit...)
}
if tp.SupplierRatingplanIDs != "" {
ratingPlanSplit := strings.Split(tp.SupplierRatingplanIDs, utils.INFIELD_SEP)
if tp.RouteRatingplanIDs != "" {
ratingPlanSplit := strings.Split(tp.RouteRatingplanIDs, utils.INFIELD_SEP)
sup.RatingPlanIDs = append(sup.RatingPlanIDs, ratingPlanSplit...)
}
if tp.SupplierResourceIDs != "" {
resSplit := strings.Split(tp.SupplierResourceIDs, utils.INFIELD_SEP)
if tp.RouteResourceIDs != "" {
resSplit := strings.Split(tp.RouteResourceIDs, utils.INFIELD_SEP)
sup.ResourceIDs = append(sup.ResourceIDs, resSplit...)
}
if tp.SupplierStatIDs != "" {
statSplit := strings.Split(tp.SupplierStatIDs, utils.INFIELD_SEP)
if tp.RouteStatIDs != "" {
statSplit := strings.Split(tp.RouteStatIDs, utils.INFIELD_SEP)
sup.StatIDs = append(sup.StatIDs, statSplit...)
}
if tp.SupplierAccountIDs != "" {
accSplit := strings.Split(tp.SupplierAccountIDs, utils.INFIELD_SEP)
if tp.RouteAccountIDs != "" {
accSplit := strings.Split(tp.RouteAccountIDs, utils.INFIELD_SEP)
sup.AccountIDs = append(sup.AccountIDs, accSplit...)
}
suppliersMap[(&utils.TenantID{Tenant: tp.Tenant, ID: tp.ID}).TenantID()][tp.SupplierID] = sup
suppliersMap[(&utils.TenantID{Tenant: tp.Tenant, ID: tp.ID}).TenantID()][tp.RouteID] = sup
}
if tp.SortingParameters != "" {
if _, has := sortingParameterMap[tenID]; !has {
@@ -1992,12 +1992,12 @@ func (tps TpSuppliers) AsTPSuppliers() (result []*utils.TPSupplierProfile) {
}
mst[(&utils.TenantID{Tenant: tp.Tenant, ID: tp.ID}).TenantID()] = th
}
result = make([]*utils.TPSupplierProfile, len(mst))
result = make([]*utils.TPRouteProfile, len(mst))
i := 0
for tntID, th := range mst {
result[i] = th
for _, supdata := range suppliersMap[tntID] {
result[i].Suppliers = append(result[i].Suppliers, supdata)
result[i].Routes = append(result[i].Routes, supdata)
}
for filterdata := range filtermap[tntID] {
result[i].FilterIDs = append(result[i].FilterIDs, filterdata)
@@ -2010,12 +2010,12 @@ func (tps TpSuppliers) AsTPSuppliers() (result []*utils.TPSupplierProfile) {
return
}
func APItoModelTPSuppliers(st *utils.TPSupplierProfile) (mdls TpSuppliers) {
if len(st.Suppliers) == 0 {
func APItoModelTPRoutes(st *utils.TPRouteProfile) (mdls TPRoutes) {
if len(st.Routes) == 0 {
return
}
for i, supl := range st.Suppliers {
mdl := &TpSupplier{
for i, supl := range st.Routes {
mdl := &TpRoute{
Tenant: st.Tenant,
Tpid: st.TPid,
ID: st.ID,
@@ -2044,119 +2044,119 @@ func APItoModelTPSuppliers(st *utils.TPSupplierProfile) (mdls TpSuppliers) {
}
}
}
mdl.SupplierID = supl.ID
mdl.RouteID = supl.ID
for i, val := range supl.AccountIDs {
if i != 0 {
mdl.SupplierAccountIDs += utils.INFIELD_SEP
mdl.RouteAccountIDs += utils.INFIELD_SEP
}
mdl.SupplierAccountIDs += val
mdl.RouteAccountIDs += val
}
for i, val := range supl.RatingPlanIDs {
if i != 0 {
mdl.SupplierRatingplanIDs += utils.INFIELD_SEP
mdl.RouteRatingplanIDs += utils.INFIELD_SEP
}
mdl.SupplierRatingplanIDs += val
mdl.RouteRatingplanIDs += val
}
for i, val := range supl.FilterIDs {
if i != 0 {
mdl.SupplierFilterIDs += utils.INFIELD_SEP
mdl.RouteFilterIDs += utils.INFIELD_SEP
}
mdl.SupplierFilterIDs += val
mdl.RouteFilterIDs += val
}
for i, val := range supl.ResourceIDs {
if i != 0 {
mdl.SupplierResourceIDs += utils.INFIELD_SEP
mdl.RouteResourceIDs += utils.INFIELD_SEP
}
mdl.SupplierResourceIDs += val
mdl.RouteResourceIDs += val
}
for i, val := range supl.StatIDs {
if i != 0 {
mdl.SupplierStatIDs += utils.INFIELD_SEP
mdl.RouteStatIDs += utils.INFIELD_SEP
}
mdl.SupplierStatIDs += val
mdl.RouteStatIDs += val
}
mdl.SupplierWeight = supl.Weight
mdl.SupplierParameters = supl.SupplierParameters
mdl.SupplierBlocker = supl.Blocker
mdl.RouteWeight = supl.Weight
mdl.RouteParameters = supl.RouteParameters
mdl.RouteBlocker = supl.Blocker
mdls = append(mdls, mdl)
}
return
}
func APItoSupplierProfile(tpSPP *utils.TPSupplierProfile, timezone string) (spp *SupplierProfile, err error) {
spp = &SupplierProfile{
Tenant: tpSPP.Tenant,
ID: tpSPP.ID,
Sorting: tpSPP.Sorting,
Weight: tpSPP.Weight,
Suppliers: make([]*Supplier, len(tpSPP.Suppliers)),
SortingParameters: make([]string, len(tpSPP.SortingParameters)),
FilterIDs: make([]string, len(tpSPP.FilterIDs)),
func APItoRouteProfile(tpRp *utils.TPRouteProfile, timezone string) (rp *RouteProfile, err error) {
rp = &RouteProfile{
Tenant: tpRp.Tenant,
ID: tpRp.ID,
Sorting: tpRp.Sorting,
Weight: tpRp.Weight,
Routes: make([]*Route, len(tpRp.Routes)),
SortingParameters: make([]string, len(tpRp.SortingParameters)),
FilterIDs: make([]string, len(tpRp.FilterIDs)),
}
for i, stp := range tpSPP.SortingParameters {
spp.SortingParameters[i] = stp
for i, stp := range tpRp.SortingParameters {
rp.SortingParameters[i] = stp
}
for i, fli := range tpSPP.FilterIDs {
spp.FilterIDs[i] = fli
for i, fli := range tpRp.FilterIDs {
rp.FilterIDs[i] = fli
}
if tpSPP.ActivationInterval != nil {
if spp.ActivationInterval, err = tpSPP.ActivationInterval.AsActivationInterval(timezone); err != nil {
if tpRp.ActivationInterval != nil {
if rp.ActivationInterval, err = tpRp.ActivationInterval.AsActivationInterval(timezone); err != nil {
return nil, err
}
}
for i, suplier := range tpSPP.Suppliers {
spp.Suppliers[i] = &Supplier{
ID: suplier.ID,
Weight: suplier.Weight,
Blocker: suplier.Blocker,
RatingPlanIDs: suplier.RatingPlanIDs,
AccountIDs: suplier.AccountIDs,
FilterIDs: suplier.FilterIDs,
ResourceIDs: suplier.ResourceIDs,
StatIDs: suplier.StatIDs,
SupplierParameters: suplier.SupplierParameters,
for i, route := range tpRp.Routes {
rp.Routes[i] = &Route{
ID: route.ID,
Weight: route.Weight,
Blocker: route.Blocker,
RatingPlanIDs: route.RatingPlanIDs,
AccountIDs: route.AccountIDs,
FilterIDs: route.FilterIDs,
ResourceIDs: route.ResourceIDs,
StatIDs: route.StatIDs,
RouteParameters: route.RouteParameters,
}
}
return spp, nil
return rp, nil
}
func SupplierProfileToAPI(spp *SupplierProfile) (tpSPP *utils.TPSupplierProfile) {
tpSPP = &utils.TPSupplierProfile{
Tenant: spp.Tenant,
ID: spp.ID,
FilterIDs: make([]string, len(spp.FilterIDs)),
func RouteProfileToAPI(rp *RouteProfile) (tpRp *utils.TPRouteProfile) {
tpRp = &utils.TPRouteProfile{
Tenant: rp.Tenant,
ID: rp.ID,
FilterIDs: make([]string, len(rp.FilterIDs)),
ActivationInterval: new(utils.TPActivationInterval),
Sorting: spp.Sorting,
SortingParameters: make([]string, len(spp.SortingParameters)),
Suppliers: make([]*utils.TPSupplier, len(spp.Suppliers)),
Weight: spp.Weight,
Sorting: rp.Sorting,
SortingParameters: make([]string, len(rp.SortingParameters)),
Routes: make([]*utils.TPRoute, len(rp.Routes)),
Weight: rp.Weight,
}
for i, supp := range spp.Suppliers {
tpSPP.Suppliers[i] = &utils.TPSupplier{
ID: supp.ID,
FilterIDs: supp.FilterIDs,
AccountIDs: supp.AccountIDs,
RatingPlanIDs: supp.RatingPlanIDs,
ResourceIDs: supp.ResourceIDs,
StatIDs: supp.StatIDs,
Weight: supp.Weight,
Blocker: supp.Blocker,
SupplierParameters: supp.SupplierParameters,
for i, route := range rp.Routes {
tpRp.Routes[i] = &utils.TPRoute{
ID: route.ID,
FilterIDs: route.FilterIDs,
AccountIDs: route.AccountIDs,
RatingPlanIDs: route.RatingPlanIDs,
ResourceIDs: route.ResourceIDs,
StatIDs: route.StatIDs,
Weight: route.Weight,
Blocker: route.Blocker,
RouteParameters: route.RouteParameters,
}
}
for i, fli := range spp.FilterIDs {
tpSPP.FilterIDs[i] = fli
for i, fli := range rp.FilterIDs {
tpRp.FilterIDs[i] = fli
}
for i, fli := range spp.SortingParameters {
tpSPP.SortingParameters[i] = fli
for i, fli := range rp.SortingParameters {
tpRp.SortingParameters[i] = fli
}
if spp.ActivationInterval != nil {
if !spp.ActivationInterval.ActivationTime.IsZero() {
tpSPP.ActivationInterval.ActivationTime = spp.ActivationInterval.ActivationTime.Format(time.RFC3339)
if rp.ActivationInterval != nil {
if !rp.ActivationInterval.ActivationTime.IsZero() {
tpRp.ActivationInterval.ActivationTime = rp.ActivationInterval.ActivationTime.Format(time.RFC3339)
}
if !spp.ActivationInterval.ExpiryTime.IsZero() {
tpSPP.ActivationInterval.ExpiryTime = spp.ActivationInterval.ExpiryTime.Format(time.RFC3339)
if !rp.ActivationInterval.ExpiryTime.IsZero() {
tpRp.ActivationInterval.ExpiryTime = rp.ActivationInterval.ExpiryTime.Format(time.RFC3339)
}
}
return

View File

@@ -348,26 +348,26 @@ func (t TBLVersion) TableName() string {
return utils.TBLVersions
}
type TpSupplier struct {
PK uint `gorm:"primary_key"`
Tpid string
Tenant string `index:"0" re:""`
ID string `index:"1" re:""`
FilterIDs string `index:"2" re:""`
ActivationInterval string `index:"3" re:""`
Sorting string `index:"4" re:""`
SortingParameters string `index:"5" re:""`
SupplierID string `index:"6" re:""`
SupplierFilterIDs string `index:"7" re:""`
SupplierAccountIDs string `index:"8" re:""`
SupplierRatingplanIDs string `index:"9" re:""`
SupplierResourceIDs string `index:"10" re:""`
SupplierStatIDs string `index:"11" re:""`
SupplierWeight float64 `index:"12" re:"\d+\.?\d*"`
SupplierBlocker bool `index:"13" re:""`
SupplierParameters string `index:"14" re:""`
Weight float64 `index:"15" re:"\d+\.?\d*"`
CreatedAt time.Time
type TpRoute struct {
PK uint `gorm:"primary_key"`
Tpid string
Tenant string `index:"0" re:""`
ID string `index:"1" re:""`
FilterIDs string `index:"2" re:""`
ActivationInterval string `index:"3" re:""`
Sorting string `index:"4" re:""`
SortingParameters string `index:"5" re:""`
RouteID string `index:"6" re:""`
RouteFilterIDs string `index:"7" re:""`
RouteAccountIDs string `index:"8" re:""`
RouteRatingplanIDs string `index:"9" re:""`
RouteResourceIDs string `index:"10" re:""`
RouteStatIDs string `index:"11" re:""`
RouteWeight float64 `index:"12" re:"\d+\.?\d*"`
RouteBlocker bool `index:"13" re:""`
RouteParameters string `index:"14" re:""`
Weight float64 `index:"15" re:"\d+\.?\d*"`
CreatedAt time.Time
}
type TPAttribute struct {

View File

@@ -22,24 +22,24 @@ import (
"github.com/cgrates/cgrates/utils"
)
func NewWeightSorter(spS *SupplierService) *WeightSorter {
return &WeightSorter{spS: spS,
func NewWeightSorter(rS *RouteService) *WeightSorter {
return &WeightSorter{rS: rS,
sorting: utils.MetaWeight}
}
// WeightSorter orders suppliers based on their weight, no cost involved
type WeightSorter struct {
sorting string
spS *SupplierService
rS *RouteService
}
func (ws *WeightSorter) SortSuppliers(prflID string,
suppls []*Supplier, suplEv *utils.CGREvent, extraOpts *optsGetSuppliers) (sortedSuppls *SortedSuppliers, err error) {
suppls []*Route, suplEv *utils.CGREvent, extraOpts *optsGetSuppliers) (sortedSuppls *SortedSuppliers, err error) {
sortedSuppls = &SortedSuppliers{ProfileID: prflID,
Sorting: ws.sorting,
SortedSuppliers: make([]*SortedSupplier, 0)}
for _, s := range suppls {
if srtSpl, pass, err := ws.spS.populateSortingData(suplEv, s, extraOpts); err != nil {
if srtSpl, pass, err := ws.rS.populateSortingData(suplEv, s, extraOpts); err != nil {
return nil, err
} else if pass && srtSpl != nil {
sortedSuppls.SortedSuppliers = append(sortedSuppls.SortedSuppliers, srtSpl)

View File

@@ -29,48 +29,48 @@ import (
"github.com/cgrates/cgrates/utils"
)
// Supplier defines supplier related information used within a SupplierProfile
type Supplier struct {
ID string // SupplierID
FilterIDs []string
AccountIDs []string
RatingPlanIDs []string // used when computing price
ResourceIDs []string // queried in some strategies
StatIDs []string // queried in some strategies
Weight float64
Blocker bool // do not process further supplier after this one
SupplierParameters string
// Route defines routes related information used within a RouteProfile
type Route struct {
ID string // SupplierID
FilterIDs []string
AccountIDs []string
RatingPlanIDs []string // used when computing price
ResourceIDs []string // queried in some strategies
StatIDs []string // queried in some strategies
Weight float64
Blocker bool // do not process further supplier after this one
RouteParameters string
cacheSupplier map[string]interface{} // cache["*ratio"]=ratio
cacheRoute map[string]interface{} // cache["*ratio"]=ratio
lazyCheckRules []*FilterRule
}
// SupplierProfile represents the configuration of a Supplier profile
type SupplierProfile struct {
// RouteProfile represents the configuration of a Supplier profile
type RouteProfile struct {
Tenant string
ID string // LCR Profile ID
FilterIDs []string
ActivationInterval *utils.ActivationInterval // Activation interval
Sorting string // Sorting strategy
SortingParameters []string
Suppliers []*Supplier
Routes []*Route
Weight float64
cache map[string]interface{}
}
// SupplierProfileWithArgDispatcher is used in replicatorV1 for dispatcher
type SupplierProfileWithArgDispatcher struct {
*SupplierProfile
type RouteProfileWithArgDispatcher struct {
*RouteProfile
*utils.ArgDispatcher
}
func (sp *SupplierProfile) compileCacheParameters() error {
if sp.Sorting == utils.MetaLoad {
func (rp *RouteProfile) compileCacheParameters() error {
if rp.Sorting == utils.MetaLoad {
// construct the map for ratio
ratioMap := make(map[string]int)
// []string{"supplierID:Ratio"}
for _, splIDWithRatio := range sp.SortingParameters {
for _, splIDWithRatio := range rp.SortingParameters {
splitted := strings.Split(splIDWithRatio, utils.CONCATENATED_KEY_SEP)
ratioVal, err := strconv.Atoi(splitted[1])
if err != nil {
@@ -78,58 +78,58 @@ func (sp *SupplierProfile) compileCacheParameters() error {
}
ratioMap[splitted[0]] = ratioVal
}
// add the ratio for each supplier
for _, supplier := range sp.Suppliers {
supplier.cacheSupplier = make(map[string]interface{})
if ratioSupplier, has := ratioMap[supplier.ID]; !has { // in case that ratio isn't defined for specific suppliers check for default
// add the ratio for each route
for _, route := range rp.Routes {
route.cacheRoute = make(map[string]interface{})
if ratioSupplier, has := ratioMap[route.ID]; !has { // in case that ratio isn't defined for specific suppliers check for default
if ratioDefault, has := ratioMap[utils.MetaDefault]; !has { // in case that *default ratio isn't defined take it from config
supplier.cacheSupplier[utils.MetaRatio] = config.CgrConfig().SupplierSCfg().DefaultRatio
route.cacheRoute[utils.MetaRatio] = config.CgrConfig().SupplierSCfg().DefaultRatio
} else {
supplier.cacheSupplier[utils.MetaRatio] = ratioDefault
route.cacheRoute[utils.MetaRatio] = ratioDefault
}
} else {
supplier.cacheSupplier[utils.MetaRatio] = ratioSupplier
route.cacheRoute[utils.MetaRatio] = ratioSupplier
}
}
}
return nil
}
// Compile is a wrapper for convenience setting up the SupplierProfile
func (sp *SupplierProfile) Compile() error {
return sp.compileCacheParameters()
// Compile is a wrapper for convenience setting up the RouteProfile
func (rp *RouteProfile) Compile() error {
return rp.compileCacheParameters()
}
// TenantID returns unique identifier of the LCRProfile in a multi-tenant environment
func (rp *SupplierProfile) TenantID() string {
func (rp *RouteProfile) TenantID() string {
return utils.ConcatenatedKey(rp.Tenant, rp.ID)
}
// SupplierProfiles is a sortable list of SupplierProfile
type SupplierProfiles []*SupplierProfile
// RouteProfiles is a sortable list of RouteProfile
type RouteProfiles []*RouteProfile
// Sort is part of sort interface, sort based on Weight
func (lps SupplierProfiles) Sort() {
func (lps RouteProfiles) Sort() {
sort.Slice(lps, func(i, j int) bool { return lps[i].Weight > lps[j].Weight })
}
// NewSupplierService initializes the Supplier Service
func NewSupplierService(dm *DataManager,
filterS *FilterS, cgrcfg *config.CGRConfig, connMgr *ConnManager) (spS *SupplierService, err error) {
spS = &SupplierService{
// NewRouteService initializes the Route Service
func NewRouteService(dm *DataManager,
filterS *FilterS, cgrcfg *config.CGRConfig, connMgr *ConnManager) (rS *RouteService, err error) {
rS = &RouteService{
dm: dm,
filterS: filterS,
cgrcfg: cgrcfg,
connMgr: connMgr,
}
if spS.sorter, err = NewSupplierSortDispatcher(spS); err != nil {
if rS.sorter, err = NewRouteSortDispatcher(rS); err != nil {
return nil, err
}
return
}
// SupplierService is the service computing Supplier queries
type SupplierService struct {
// RouteService is the service computing route queries
type RouteService struct {
dm *DataManager
filterS *FilterS
cgrcfg *config.CGRConfig
@@ -138,17 +138,17 @@ type SupplierService struct {
}
// ListenAndServe will initialize the service
func (spS *SupplierService) ListenAndServe(exitChan chan bool) error {
utils.Logger.Info(fmt.Sprintf("<%s> starting <%s> subsystem", utils.CoreS, utils.SupplierS))
func (rpS *RouteService) ListenAndServe(exitChan chan bool) error {
utils.Logger.Info(fmt.Sprintf("<%s> starting <%s> subsystem", utils.CoreS, utils.RouteS))
e := <-exitChan
exitChan <- e // put back for the others listening for shutdown request
return nil
}
// Shutdown is called to shutdown the service
func (spS *SupplierService) Shutdown() error {
utils.Logger.Info(fmt.Sprintf("<%s> service shutdown initialized", utils.SupplierS))
utils.Logger.Info(fmt.Sprintf("<%s> service shutdown complete", utils.SupplierS))
func (rpS *RouteService) Shutdown() error {
utils.Logger.Info(fmt.Sprintf("<%s> service shutdown initialized", utils.RouteS))
utils.Logger.Info(fmt.Sprintf("<%s> service shutdown complete", utils.RouteS))
return nil
}

View File

@@ -1089,21 +1089,21 @@ type TPFilter struct {
Values []string // Filter definition
}
// TPSupplier is used in TPSupplierProfile
type TPSupplier struct {
ID string // SupplierID
FilterIDs []string
AccountIDs []string
RatingPlanIDs []string // used when computing price
ResourceIDs []string // queried in some strategies
StatIDs []string // queried in some strategies
Weight float64
Blocker bool
SupplierParameters string
// TPRoute is used in TPRouteProfile
type TPRoute struct {
ID string // RouteID
FilterIDs []string
AccountIDs []string
RatingPlanIDs []string // used when computing price
ResourceIDs []string // queried in some strategies
StatIDs []string // queried in some strategies
Weight float64
Blocker bool
RouteParameters string
}
// TPSupplierProfile is used in APIs to manage remotely offline SupplierProfile
type TPSupplierProfile struct {
// TPRouteProfile is used in APIs to manage remotely offline RouteProfile
type TPRouteProfile struct {
TPid string
Tenant string
ID string
@@ -1111,7 +1111,7 @@ type TPSupplierProfile struct {
ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires
Sorting string
SortingParameters []string
Suppliers []*TPSupplier
Routes []*TPRoute
Weight float64
}

View File

@@ -558,15 +558,14 @@ const (
Async = "Async"
Sorting = "Sorting"
SortingParameters = "SortingParameters"
SupplierAccountIDs = "SupplierAccountIDs"
SupplierRatingplanIDs = "SupplierRatingplanIDs"
SupplierStatIDs = "SupplierStatIDs"
SupplierWeight = "SupplierWeight"
SupplierParameters = "SupplierParameters"
SupplierBlocker = "SupplierBlocker"
SupplierResourceIDs = "SupplierResourceIDs"
SupplierID = "SupplierID"
SupplierFilterIDs = "SupplierFilterIDs"
RouteAccountIDs = "RouteAccountIDs"
RouteRatingplanIDs = "RouteRatingplanIDs"
RouteStatIDs = "RouteStatIDs"
RouteWeight = "RouteWeight"
RouteParameters = "RouteParameters"
RouteBlocker = "RouteBlocker"
RouteResourceIDs = "RouteResourceIDs"
RouteFilterIDs = "RouteFilterIDs"
AttributeFilterIDs = "AttributeFilterIDs"
QueueLength = "QueueLength"
TTL = "TTL"
@@ -761,7 +760,7 @@ const (
const (
SessionS = "SessionS"
AttributeS = "AttributeS"
SupplierS = "SupplierS"
RouteS = "RouteS"
ResourceS = "ResourceS"
StatService = "StatS"
FilterS = "FilterS"