diff --git a/engine/libroutes.go b/engine/libroutes.go new file mode 100644 index 000000000..62d79fc4e --- /dev/null +++ b/engine/libroutes.go @@ -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 +*/ + +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 +} diff --git a/engine/libsuppliers_test.go b/engine/libroutes_test.go similarity index 100% rename from engine/libsuppliers_test.go rename to engine/libroutes_test.go diff --git a/engine/libsuppliers.go b/engine/libsuppliers.go deleted file mode 100644 index dfc244015..000000000 --- a/engine/libsuppliers.go +++ /dev/null @@ -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 -*/ - -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 -} diff --git a/engine/model_helpers.go b/engine/model_helpers.go index fca07c97c..c62ccb878 100644 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -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 diff --git a/engine/models.go b/engine/models.go index d86933f39..6bba9b7f9 100644 --- a/engine/models.go +++ b/engine/models.go @@ -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 { diff --git a/engine/spls_highestcost.go b/engine/route_highestcost.go similarity index 100% rename from engine/spls_highestcost.go rename to engine/route_highestcost.go diff --git a/engine/spls_leastcost.go b/engine/route_leastcost.go similarity index 100% rename from engine/spls_leastcost.go rename to engine/route_leastcost.go diff --git a/engine/spls_load_distribution.go b/engine/route_load_distribution.go similarity index 100% rename from engine/spls_load_distribution.go rename to engine/route_load_distribution.go diff --git a/engine/spls_qos.go b/engine/route_qos.go similarity index 100% rename from engine/spls_qos.go rename to engine/route_qos.go diff --git a/engine/spls_reas.go b/engine/route_reas.go similarity index 100% rename from engine/spls_reas.go rename to engine/route_reas.go diff --git a/engine/spls_reds.go b/engine/route_reds.go similarity index 100% rename from engine/spls_reds.go rename to engine/route_reds.go diff --git a/engine/spls_weight.go b/engine/route_weight.go similarity index 80% rename from engine/spls_weight.go rename to engine/route_weight.go index 5fea0188c..9b0dbe392 100755 --- a/engine/spls_weight.go +++ b/engine/route_weight.go @@ -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) diff --git a/engine/suppliers.go b/engine/routes.go similarity index 89% rename from engine/suppliers.go rename to engine/routes.go index 40e8e375d..8ecf0733e 100644 --- a/engine/suppliers.go +++ b/engine/routes.go @@ -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 } diff --git a/engine/suppliers_test.go b/engine/routes_test.go similarity index 100% rename from engine/suppliers_test.go rename to engine/routes_test.go diff --git a/utils/apitpdata.go b/utils/apitpdata.go index aab5ccb61..e9ffd19f3 100755 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -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 } diff --git a/utils/consts.go b/utils/consts.go index 2e57216c3..765e7d705 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -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"