diff --git a/utils/coverage.html b/utils/coverage.html
deleted file mode 100644
index 13e5b1725..000000000
--- a/utils/coverage.html
+++ /dev/null
@@ -1,10990 +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 utils
-
-import (
- "fmt"
- "sort"
- "strings"
- "time"
-)
-
-// Used to extract ids from stordb
-type TPDistinctIds []string
-
-func (tpdi TPDistinctIds) String() string {
- return strings.Join(tpdi, FIELDS_SEP)
-}
-
-type PaginatorWithSearch struct {
- *Paginator
- Search string // Global matching pattern in items returned, partially used in some APIs
-}
-
-// Paginate stuff around items returned
-type Paginator struct {
- Limit *int // Limit the number of items returned
- Offset *int // Offset of the first item returned (eg: use Limit*Page in case of PerPage items)
-
-}
-
-func (pgnt *Paginator) PaginateStringSlice(in []string) (out []string) {
- if len(in) == 0 {
- return
- }
- var limit, offset int
- if pgnt.Limit != nil && *pgnt.Limit > 0 {
- limit = *pgnt.Limit
- }
- if pgnt.Offset != nil && *pgnt.Offset > 0 {
- offset = *pgnt.Offset
- }
- if limit == 0 && offset == 0 {
- return in
- }
- if offset > len(in) {
- return
- }
- if offset != 0 && limit != 0 {
- limit = limit + offset
- }
- if limit == 0 || limit > len(in) {
- limit = len(in)
- }
- ret := in[offset:limit]
- out = make([]string, len(ret))
- for i, itm := range ret {
- out[i] = itm
- }
- return
-}
-
-// TPDestination represents one destination in storDB
-type TPDestination struct {
- TPid string // Tariff plan id
- ID string // Destination id
- Prefixes []string // Prefixes attached to this destination
-}
-
-// This file deals with tp_* data definition
-
-type TPRate struct {
- TPid string // Tariff plan id
- ID string // Rate id
- RateSlots []*RateSlot // One or more RateSlots
-}
-
-// Needed so we make sure we always use SetDurations() on a newly created value
-func NewRateSlot(connectFee, rate float64, rateUnit, rateIncrement, grpInterval string) (*RateSlot, error) {
- rs := &RateSlot{
- ConnectFee: connectFee,
- Rate: rate,
- RateUnit: rateUnit,
- RateIncrement: rateIncrement,
- GroupIntervalStart: grpInterval,
- }
- if err := rs.SetDurations(); err != nil {
- return nil, err
- }
- return rs, nil
-}
-
-type RateSlot struct {
- ConnectFee float64 // ConnectFee applied once the call is answered
- Rate float64 // Rate applied
- RateUnit string // Number of billing units this rate applies to
- RateIncrement string // This rate will apply in increments of duration
- GroupIntervalStart string // Group position
- rateUnitDur time.Duration
- rateIncrementDur time.Duration
- groupIntervalStartDur time.Duration
- tag string // load validation only
-}
-
-// Used to set the durations we need out of strings
-func (rs *RateSlot) SetDurations() error {
- var err error
- if rs.rateUnitDur, err = ParseDurationWithNanosecs(rs.RateUnit); err != nil {
- return err
- }
- if rs.rateIncrementDur, err = ParseDurationWithNanosecs(rs.RateIncrement); err != nil {
- return err
- }
- if rs.groupIntervalStartDur, err = ParseDurationWithNanosecs(rs.GroupIntervalStart); err != nil {
- return err
- }
- return nil
-}
-func (rs *RateSlot) RateUnitDuration() time.Duration {
- return rs.rateUnitDur
-}
-func (rs *RateSlot) RateIncrementDuration() time.Duration {
- return rs.rateIncrementDur
-}
-func (rs *RateSlot) GroupIntervalStartDuration() time.Duration {
- return rs.groupIntervalStartDur
-}
-
-type TPDestinationRate struct {
- TPid string // Tariff plan id
- ID string // DestinationRate profile id
- DestinationRates []*DestinationRate // Set of destinationid-rateid bindings
-}
-
-type DestinationRate struct {
- DestinationId string // The destination identity
- RateId string // The rate identity
- Rate *TPRate
- RoundingMethod string
- RoundingDecimals int
- MaxCost float64
- MaxCostStrategy string
-}
-
-type ApierTPTiming struct {
- TPid string // Tariff plan id
- ID string // Timing id
- Years string // semicolon separated list of years this timing is valid on, *any supported
- Months string // semicolon separated list of months this timing is valid on, *any supported
- MonthDays string // semicolon separated list of month's days this timing is valid on, *any supported
- WeekDays string // semicolon separated list of week day names this timing is valid on *any supported
- Time string // String representing the time this timing starts on
-}
-
-type TPTiming struct {
- ID string
- Years Years
- Months Months
- MonthDays MonthDays
- WeekDays WeekDays
- StartTime string
- EndTime string
-}
-
-func NewTiming(ID, years, mounths, mounthdays, weekdays, time string) (rt *TPTiming) {
- rt = &TPTiming{}
- rt.ID = ID
- rt.Years.Parse(years, INFIELD_SEP)
- rt.Months.Parse(mounths, INFIELD_SEP)
- rt.MonthDays.Parse(mounthdays, INFIELD_SEP)
- rt.WeekDays.Parse(weekdays, INFIELD_SEP)
- times := strings.Split(time, INFIELD_SEP)
- rt.StartTime = times[0]
- if len(times) > 1 {
- rt.EndTime = times[1]
- }
- return
-}
-
-type TPRatingPlan struct {
- TPid string // Tariff plan id
- ID string // RatingPlan profile id
- RatingPlanBindings []*TPRatingPlanBinding // Set of destinationid-rateid bindings
-}
-
-type TPRatingPlanBinding struct {
- DestinationRatesId string // The DestinationRate identity
- TimingId string // The timing identity
- Weight float64 // Binding priority taken into consideration when more DestinationRates are active on a time slot
- timing *TPTiming // Not exporting it via JSON
-}
-
-func (self *TPRatingPlanBinding) SetTiming(tm *TPTiming) {
- self.timing = tm
-}
-
-func (self *TPRatingPlanBinding) Timing() *TPTiming {
- return self.timing
-}
-
-type TPRatingProfile struct {
- TPid string // Tariff plan id
- LoadId string // Gives ability to load specific RatingProfile based on load identifier, hence being able to keep history also in stordb
- Tenant string // Tenant's Id
- Category string // TypeOfRecord
- Subject string // Rating subject, usually the same as account
- RatingPlanActivations []*TPRatingActivation // Activate rate profiles at specific time
-}
-
-// Used as key in nosql db (eg: redis)
-func (rpf *TPRatingProfile) KeyId() string {
- return ConcatenatedKey(META_OUT,
- rpf.Tenant, rpf.Category, rpf.Subject)
-}
-
-func (rpf *TPRatingProfile) GetId() string {
- return ConcatenatedKey(rpf.LoadId, META_OUT,
- rpf.Tenant, rpf.Category, rpf.Subject)
-}
-
-func (rpf *TPRatingProfile) SetRatingProfileID(id string) error {
- ids := strings.Split(id, CONCATENATED_KEY_SEP)
- if len(ids) != 4 {
- return fmt.Errorf("Wrong TPRatingProfileId: %s", id)
- }
- rpf.LoadId = ids[0]
- rpf.Tenant = ids[1]
- rpf.Category = ids[2]
- rpf.Subject = ids[3]
- return nil
-}
-
-type AttrSetRatingProfile struct {
- Tenant string // Tenant's Id
- Category string // TypeOfRecord
- Subject string // Rating subject, usually the same as account
- Overwrite bool // Overwrite if exists
- RatingPlanActivations []*TPRatingActivation // Activate rating plans at specific time
- Cache *string
-}
-
-type AttrGetRatingProfile struct {
- Tenant string // Tenant's Id
- Category string // TypeOfRecord
- Subject string // Rating subject, usually the same as account
-}
-
-func (self *AttrGetRatingProfile) GetID() string {
- return ConcatenatedKey(META_OUT, self.Tenant, self.Category, self.Subject)
-}
-
-type TPRatingActivation struct {
- ActivationTime string // Time when this profile will become active, defined as unix epoch time
- RatingPlanId string // Id of RatingPlan profile
- FallbackSubjects string // So we follow the api
-}
-
-// Helper to return the subject fallback keys we need in dataDb
-func FallbackSubjKeys(tenant, tor, fallbackSubjects string) []string {
- var sslice sort.StringSlice
- if len(fallbackSubjects) != 0 {
- for _, fbs := range strings.Split(fallbackSubjects, string(FALLBACK_SEP)) {
- newKey := ConcatenatedKey(META_OUT, tenant, tor, fbs)
- i := sslice.Search(newKey)
- if i < len(sslice) && sslice[i] != newKey {
- // not found so insert it
- sslice = append(sslice, "")
- copy(sslice[i+1:], sslice[i:])
- sslice[i] = newKey
- } else if i == len(sslice) {
- // not found and at the end
- sslice = append(sslice, newKey)
- } // newKey was found
- }
- }
- return sslice
-}
-
-type AttrSetDestination struct {
- Id string
- Prefixes []string
- Overwrite bool
-}
-
-type AttrTPRatingProfileIds struct {
- TPid string // Tariff plan id
- Tenant string // Tenant's Id
- Category string // TypeOfRecord
- Subject string // Rating subject, usually the same as account
-}
-
-type TPActions struct {
- TPid string // Tariff plan id
- ID string // Actions id
- Actions []*TPAction // Set of actions this Actions profile will perform
-}
-
-type TPAction struct {
- Identifier string // Identifier mapped in the code
- BalanceId string // Balance identification string (account scope)
- BalanceUuid string // Balance identification string (global scope)
- BalanceType string // Type of balance the action will operate on
- Units string // Number of units to add/deduct
- ExpiryTime string // Time when the units will expire
- Filter string // The condition on balances that is checked before the action
- TimingTags string // Timing when balance is active
- DestinationIds string // Destination profile id
- RatingSubject string // Reference a rate subject defined in RatingProfiles
- Categories string // category filter for balances
- SharedGroups string // Reference to a shared group
- BalanceWeight string // Balance weight
- ExtraParameters string
- BalanceBlocker string
- BalanceDisabled string
- Weight float64 // Action's weight
-}
-
-type TPSharedGroups struct {
- TPid string
- ID string
- SharedGroups []*TPSharedGroup
-}
-
-type TPSharedGroup struct {
- Account string
- Strategy string
- RatingSubject string
-}
-
-type TPActionPlan struct {
- TPid string // Tariff plan id
- ID string // ActionPlan id
- ActionPlan []*TPActionTiming // Set of ActionTiming bindings this profile will group
-}
-
-type TPActionTiming struct {
- ActionsId string // Actions id
- TimingId string // Timing profile id
- Weight float64 // Binding's weight
-}
-
-type TPActionTriggers struct {
- TPid string // Tariff plan id
- ID string // action trigger id
- ActionTriggers []*TPActionTrigger // Set of triggers grouped in this profile
-}
-
-type TPActionTrigger struct {
- Id string // group id
- UniqueID string // individual id
- ThresholdType string // This threshold type
- ThresholdValue float64 // Threshold
- Recurrent bool // reset executed flag each run
- MinSleep string // Minimum duration between two executions in case of recurrent triggers
- ExpirationDate string // Trigger expiration
- ActivationDate string // Trigger activation
- BalanceId string // The id of the balance in the account
- BalanceType string // Type of balance this trigger monitors
- BalanceDestinationIds string // filter for balance
- BalanceWeight string // filter for balance
- BalanceExpirationDate string // filter for balance
- BalanceTimingTags string // filter for balance
- BalanceRatingSubject string // filter for balance
- BalanceCategories string // filter for balance
- BalanceSharedGroups string // filter for balance
- BalanceBlocker string // filter for balance
- BalanceDisabled string // filter for balance
- ActionsId string // Actions which will execute on threshold reached
- Weight float64 // weight
-}
-
-type TPAccountActions struct {
- TPid string // Tariff plan id
- LoadId string // LoadId, used to group actions on a load
- Tenant string // Tenant's Id
- Account string // Account name
- ActionPlanId string // Id of ActionPlan profile to use
- ActionTriggersId string // Id of ActionTriggers profile to use
- AllowNegative bool
- Disabled bool
-}
-
-// Returns the id used in some nosql dbs (eg: redis)
-func (aa *TPAccountActions) KeyId() string {
- return ConcatenatedKey(aa.Tenant, aa.Account)
-}
-
-func (aa *TPAccountActions) GetId() string {
- return aa.LoadId + CONCATENATED_KEY_SEP + aa.Tenant + CONCATENATED_KEY_SEP + aa.Account
-}
-
-func (aa *TPAccountActions) SetAccountActionsId(id string) error {
- ids := strings.Split(id, CONCATENATED_KEY_SEP)
- if len(ids) != 3 {
- return fmt.Errorf("Wrong TP Account Action Id: %s", id)
- }
- aa.LoadId = ids[0]
- aa.Tenant = ids[1]
- aa.Account = ids[2]
- return nil
-}
-
-type AttrGetAccount struct {
- Tenant string
- Account string
-}
-
-type AttrGetAccounts struct {
- Tenant string
- AccountIDs []string
- Offset int // Set the item offset
- Limit int // Limit number of items retrieved
- Filter map[string]bool
-}
-
-type ArgsCache struct {
- DestinationIDs []string
- ReverseDestinationIDs []string
- RatingPlanIDs []string
- RatingProfileIDs []string
- ActionIDs []string
- ActionPlanIDs []string
- AccountActionPlanIDs []string
- ActionTriggerIDs []string
- SharedGroupIDs []string
- ResourceProfileIDs []string
- ResourceIDs []string
- StatsQueueIDs []string
- StatsQueueProfileIDs []string
- ThresholdIDs []string
- ThresholdProfileIDs []string
- FilterIDs []string
- SupplierProfileIDs []string
- AttributeProfileIDs []string
- ChargerProfileIDs []string
- DispatcherProfileIDs []string
- DispatcherHostIDs []string
- DispatcherRoutesIDs []string
-}
-
-// Data used to do remote cache reloads via api
-type AttrReloadCache struct {
- ArgsCache
- FlushAll bool // If provided, cache flush will be executed before any action
-}
-
-// InitAttrReloadCache initialize AttrReloadCache with empty string slice
-func InitAttrReloadCache() (rpl AttrReloadCache) {
- rpl.DestinationIDs = []string{}
- rpl.ReverseDestinationIDs = []string{}
- rpl.RatingPlanIDs = []string{}
- rpl.RatingProfileIDs = []string{}
- rpl.ActionIDs = []string{}
- rpl.ActionPlanIDs = []string{}
- rpl.AccountActionPlanIDs = []string{}
- rpl.ActionTriggerIDs = []string{}
- rpl.SharedGroupIDs = []string{}
- rpl.ResourceProfileIDs = []string{}
- rpl.ResourceIDs = []string{}
- rpl.StatsQueueIDs = []string{}
- rpl.StatsQueueProfileIDs = []string{}
- rpl.ThresholdIDs = []string{}
- rpl.ThresholdProfileIDs = []string{}
- rpl.FilterIDs = []string{}
- rpl.SupplierProfileIDs = []string{}
- rpl.AttributeProfileIDs = []string{}
- rpl.ChargerProfileIDs = []string{}
- rpl.DispatcherProfileIDs = []string{}
- rpl.DispatcherHostIDs = []string{}
- rpl.DispatcherRoutesIDs = []string{}
- return
-}
-
-type CacheKeys struct {
-}
-
-type AttrExpFileCdrs struct {
- CdrFormat *string // Cdr output file format <CdreCdrFormats>
- FieldSeparator *string // Separator used between fields
- ExportId *string // Optional exportid
- ExportDir *string // If provided it overwrites the configured export directory
- ExportFileName *string // If provided the output filename will be set to this
- ExportTemplate *string // Exported fields template <""|fld1,fld2|*xml:instance_name>
- CgrIds []string // If provided, it will filter based on the cgrids present in list
- MediationRunIds []string // If provided, it will filter on mediation runid
- TORs []string // If provided, filter on TypeOfRecord
- CdrHosts []string // If provided, it will filter cdrhost
- CdrSources []string // If provided, it will filter cdrsource
- ReqTypes []string // If provided, it will fiter reqtype
- Tenants []string // If provided, it will filter tenant
- Categories []string // If provided, it will filter çategory
- Accounts []string // If provided, it will filter account
- Subjects []string // If provided, it will filter the rating subject
- DestinationPrefixes []string // If provided, it will filter on destination prefix
- OrderIdStart *int64 // Export from this order identifier
- OrderIdEnd *int64 // Export smaller than this order identifier
- TimeStart string // If provided, it will represent the starting of the CDRs interval (>=)
- TimeEnd string // If provided, it will represent the end of the CDRs interval (<)
- SkipErrors bool // Do not export errored CDRs
- SkipRated bool // Do not export rated CDRs
- SuppressCgrIds bool // Disable CgrIds reporting in reply/ExportedCgrIds and reply/UnexportedCgrIds
- Paginator
-}
-
-func (aefc *AttrExpFileCdrs) AsCDRsFilter(timezone string) (*CDRsFilter, error) {
- cdrFltr := &CDRsFilter{
- CGRIDs: aefc.CgrIds,
- RunIDs: aefc.MediationRunIds,
- ToRs: aefc.TORs,
- OriginHosts: aefc.CdrHosts,
- Sources: aefc.CdrSources,
- RequestTypes: aefc.ReqTypes,
- Tenants: aefc.Tenants,
- Categories: aefc.Categories,
- Accounts: aefc.Accounts,
- Subjects: aefc.Subjects,
- DestinationPrefixes: aefc.DestinationPrefixes,
- OrderIDStart: aefc.OrderIdStart,
- OrderIDEnd: aefc.OrderIdEnd,
- Paginator: aefc.Paginator,
- }
- if len(aefc.TimeStart) != 0 {
- if answerTimeStart, err := ParseTimeDetectLayout(aefc.TimeStart, timezone); err != nil {
- return nil, err
- } else {
- cdrFltr.AnswerTimeStart = &answerTimeStart
- }
- }
- if len(aefc.TimeEnd) != 0 {
- if answerTimeEnd, err := ParseTimeDetectLayout(aefc.TimeEnd, timezone); err != nil {
- return nil, err
- } else {
- cdrFltr.AnswerTimeEnd = &answerTimeEnd
- }
- }
- if aefc.SkipRated {
- cdrFltr.MaxCost = Float64Pointer(-1.0)
- } else if aefc.SkipErrors {
- cdrFltr.MinCost = Float64Pointer(0.0)
- cdrFltr.MaxCost = Float64Pointer(-1.0)
- }
- return cdrFltr, nil
-}
-
-type ExportedFileCdrs struct {
- ExportedFilePath string // Full path to the newly generated export file
- TotalRecords int // Number of CDRs to be exported
- TotalCost float64 // Sum of all costs in exported CDRs
- FirstOrderId, LastOrderId int64 // The order id of the last exported CDR
- ExportedCgrIds []string // List of successfuly exported cgrids in the file
- UnexportedCgrIds map[string]string // Map of errored CDRs, map key is cgrid, value will be the error string
-}
-
-type AttrGetCdrs struct {
- CgrIds []string // If provided, it will filter based on the cgrids present in list
- MediationRunIds []string // If provided, it will filter on mediation runid
-
- TORs []string // If provided, filter on TypeOfRecord
- CdrHosts []string // If provided, it will filter cdrhost
- CdrSources []string // If provided, it will filter cdrsource
- ReqTypes []string // If provided, it will fiter reqtype
- Tenants []string // If provided, it will filter tenant
- Categories []string // If provided, it will filter çategory
- Accounts []string // If provided, it will filter account
- Subjects []string // If provided, it will filter the rating subject
- DestinationPrefixes []string // If provided, it will filter on destination prefix
- RatedAccounts []string // If provided, it will filter ratedaccount
- RatedSubjects []string // If provided, it will filter the ratedsubject
- OrderIdStart *int64 // Export from this order identifier
- OrderIdEnd *int64 // Export smaller than this order identifier
- TimeStart string // If provided, it will represent the starting of the CDRs interval (>=)
- TimeEnd string // If provided, it will represent the end of the CDRs interval (<)
- SkipErrors bool // Do not export errored CDRs
- SkipRated bool // Do not export rated CDRs
- OrderBy string // Ascendent/Descendent
- Paginator
-}
-
-func (fltr *AttrGetCdrs) AsCDRsFilter(timezone string) (cdrFltr *CDRsFilter, err error) {
- if fltr == nil {
- return
- }
- cdrFltr = &CDRsFilter{
- CGRIDs: fltr.CgrIds,
- RunIDs: fltr.MediationRunIds,
- ToRs: fltr.TORs,
- OriginHosts: fltr.CdrHosts,
- Sources: fltr.CdrSources,
- RequestTypes: fltr.ReqTypes,
- Tenants: fltr.Tenants,
- Categories: fltr.Categories,
- Accounts: fltr.Accounts,
- Subjects: fltr.Subjects,
- DestinationPrefixes: fltr.DestinationPrefixes,
- OrderIDStart: fltr.OrderIdStart,
- OrderIDEnd: fltr.OrderIdEnd,
- Paginator: fltr.Paginator,
- OrderBy: fltr.OrderBy,
- }
- if len(fltr.TimeStart) != 0 {
- if answerTimeStart, err := ParseTimeDetectLayout(fltr.TimeStart, timezone); err != nil {
- return nil, err
- } else {
- cdrFltr.AnswerTimeStart = &answerTimeStart
- }
- }
- if len(fltr.TimeEnd) != 0 {
- if answerTimeEnd, err := ParseTimeDetectLayout(fltr.TimeEnd, timezone); err != nil {
- return nil, err
- } else {
- cdrFltr.AnswerTimeEnd = &answerTimeEnd
- }
- }
- if fltr.SkipRated {
- cdrFltr.MaxCost = Float64Pointer(-1.0)
- } else if fltr.SkipErrors {
- cdrFltr.MinCost = Float64Pointer(0.0)
- cdrFltr.MaxCost = Float64Pointer(-1.0)
- }
- return
-}
-
-type AttrLoadTpFromFolder struct {
- FolderPath string // Take files from folder absolute path
- DryRun bool // Do not write to database but parse only
- Validate bool // Run structural checks on data
- Recursive bool // load data recursive
- ArgDispatcher *ArgDispatcher
- Caching *string
-}
-
-type AttrImportTPFromFolder struct {
- TPid string
- FolderPath string
- RunId string
- CsvSeparator string
- ArgDispatcher *ArgDispatcher
-}
-
-func NewTAFromAccountKey(accountKey string) (*TenantAccount, error) {
- accountSplt := strings.Split(accountKey, CONCATENATED_KEY_SEP)
- if len(accountSplt) != 2 {
- return nil, fmt.Errorf("Unsupported format for TenantAccount: %s", accountKey)
- }
- return &TenantAccount{accountSplt[0], accountSplt[1]}, nil
-}
-
-type TenantAccount struct {
- Tenant, Account string
-}
-
-type AttrDirExportTP struct {
- TPid *string
- FileFormat *string // Format of the exported file <csv>
- FieldSeparator *string // Separator used between fields
- ExportPath *string // If provided it overwrites the configured export path
- Compress *bool // If true the folder will be compressed after export performed
-}
-
-type ExportedTPStats struct {
- ExportPath string // Full path to the newly generated export file
- ExportedFiles []string // List of exported files
- Compressed bool
-}
-
-// CDRsFilter is a filter used to get records out of storDB
-type CDRsFilter struct {
- CGRIDs []string // If provided, it will filter based on the cgrids present in list
- NotCGRIDs []string // Filter specific CgrIds out
- RunIDs []string // If provided, it will filter on mediation runid
- NotRunIDs []string // Filter specific runIds out
- OriginIDs []string // If provided, it will filter on OriginIDs
- NotOriginIDs []string // Filter specific OriginIDs out
- OriginHosts []string // If provided, it will filter cdrhost
- NotOriginHosts []string // Filter out specific cdr hosts
- Sources []string // If provided, it will filter cdrsource
- NotSources []string // Filter out specific CDR sources
- ToRs []string // If provided, filter on TypeOfRecord
- NotToRs []string // Filter specific TORs out
- RequestTypes []string // If provided, it will fiter reqtype
- NotRequestTypes []string // Filter out specific request types
- Tenants []string // If provided, it will filter tenant
- NotTenants []string // If provided, it will filter tenant
- Categories []string // If provided, it will filter çategory
- NotCategories []string // Filter out specific categories
- Accounts []string // If provided, it will filter account
- NotAccounts []string // Filter out specific Accounts
- Subjects []string // If provided, it will filter the rating subject
- NotSubjects []string // Filter out specific subjects
- DestinationPrefixes []string // If provided, it will filter on destination prefix
- NotDestinationPrefixes []string // Filter out specific destination prefixes
- Costs []float64 // Query based on costs specified
- NotCosts []float64 // Filter out specific costs out from result
- ExtraFields map[string]string // Query based on extra fields content
- NotExtraFields map[string]string // Filter out based on extra fields content
- OrderIDStart *int64 // Export from this order identifier
- OrderIDEnd *int64 // Export smaller than this order identifier
- SetupTimeStart *time.Time // Start of interval, bigger or equal than configured
- SetupTimeEnd *time.Time // End interval, smaller than setupTime
- AnswerTimeStart *time.Time // Start of interval, bigger or equal than configured
- AnswerTimeEnd *time.Time // End interval, smaller than answerTime
- CreatedAtStart *time.Time // Start of interval, bigger or equal than configured
- CreatedAtEnd *time.Time // End interval, smaller than
- UpdatedAtStart *time.Time // Start of interval, bigger or equal than configured
- UpdatedAtEnd *time.Time // End interval, smaller than
- MinUsage string // Start of the usage interval (>=)
- MaxUsage string // End of the usage interval (<)
- MinCost *float64 // Start of the cost interval (>=)
- MaxCost *float64 // End of the usage interval (<)
- Unscoped bool // Include soft-deleted records in results
- Count bool // If true count the items instead of returning data
- OrderBy string // Can be ordered by OrderID,AnswerTime,SetupTime,Cost,Usage
- Paginator
-}
-
-// Prepare will sort all the slices in order to search more faster
-func (fltr *CDRsFilter) Prepare() {
- sort.Strings(fltr.CGRIDs)
- sort.Strings(fltr.NotCGRIDs)
- sort.Strings(fltr.RunIDs)
- sort.Strings(fltr.NotRunIDs)
- sort.Strings(fltr.OriginIDs)
- sort.Strings(fltr.NotOriginIDs)
- sort.Strings(fltr.OriginHosts)
- sort.Strings(fltr.NotOriginHosts)
- sort.Strings(fltr.Sources)
- sort.Strings(fltr.NotSources)
- sort.Strings(fltr.ToRs)
- sort.Strings(fltr.NotToRs)
- sort.Strings(fltr.RequestTypes)
- sort.Strings(fltr.NotRequestTypes)
- sort.Strings(fltr.Tenants)
- sort.Strings(fltr.NotTenants)
- sort.Strings(fltr.Categories)
- sort.Strings(fltr.NotCategories)
- sort.Strings(fltr.Accounts)
- sort.Strings(fltr.NotAccounts)
- sort.Strings(fltr.Subjects)
- sort.Strings(fltr.NotSubjects)
- // sort.Strings(fltr.DestinationPrefixes)
- // sort.Strings(fltr.NotDestinationPrefixes)
-
- sort.Float64s(fltr.Costs)
- sort.Float64s(fltr.NotCosts)
-}
-
-// RPCCDRsFilter is a filter used in Rpc calls
-// RPCCDRsFilter is slightly different than CDRsFilter by using string instead of Time filters
-type RPCCDRsFilter struct {
- CGRIDs []string // If provided, it will filter based on the cgrids present in list
- NotCGRIDs []string // Filter specific CgrIds out
- RunIDs []string // If provided, it will filter on mediation runid
- NotRunIDs []string // Filter specific runIds out
- OriginIDs []string // If provided, it will filter on OriginIDs
- NotOriginIDs []string // Filter specific OriginIDs out
- OriginHosts []string // If provided, it will filter cdrhost
- NotOriginHosts []string // Filter out specific cdr hosts
- Sources []string // If provided, it will filter cdrsource
- NotSources []string // Filter out specific CDR sources
- ToRs []string // If provided, filter on TypeOfRecord
- NotToRs []string // Filter specific TORs out
- RequestTypes []string // If provided, it will fiter reqtype
- NotRequestTypes []string // Filter out specific request types
- Tenants []string // If provided, it will filter tenant
- NotTenants []string // If provided, it will filter tenant
- Categories []string // If provided, it will filter çategory
- NotCategories []string // Filter out specific categories
- Accounts []string // If provided, it will filter account
- NotAccounts []string // Filter out specific Accounts
- Subjects []string // If provided, it will filter the rating subject
- NotSubjects []string // Filter out specific subjects
- DestinationPrefixes []string // If provided, it will filter on destination prefix
- NotDestinationPrefixes []string // Filter out specific destination prefixes
- Costs []float64 // Query based on costs specified
- NotCosts []float64 // Filter out specific costs out from result
- ExtraFields map[string]string // Query based on extra fields content
- NotExtraFields map[string]string // Filter out based on extra fields content
- SetupTimeStart string // Start of interval, bigger or equal than configured
- SetupTimeEnd string // End interval, smaller than setupTime
- AnswerTimeStart string // Start of interval, bigger or equal than configured
- AnswerTimeEnd string // End interval, smaller than answerTime
- CreatedAtStart string // Start of interval, bigger or equal than configured
- CreatedAtEnd string // End interval, smaller than
- UpdatedAtStart string // Start of interval, bigger or equal than configured
- UpdatedAtEnd string // End interval, smaller than
- MinUsage string // Start of the usage interval (>=)
- MaxUsage string // End of the usage interval (<)
- OrderBy string // Ascendent/Descendent
- ExtraArgs map[string]any // it will contain optional arguments like: OrderIDStart,OrderIDEnd,MinCost and MaxCost
- Paginator // Add pagination
-}
-
-func (fltr *RPCCDRsFilter) AsCDRsFilter(timezone string) (cdrFltr *CDRsFilter, err error) {
- if fltr == nil {
- cdrFltr = new(CDRsFilter)
- return
- }
- cdrFltr = &CDRsFilter{
- CGRIDs: fltr.CGRIDs,
- NotCGRIDs: fltr.NotCGRIDs,
- RunIDs: fltr.RunIDs,
- NotRunIDs: fltr.NotRunIDs,
- OriginIDs: fltr.OriginIDs,
- NotOriginIDs: fltr.NotOriginIDs,
- ToRs: fltr.ToRs,
- NotToRs: fltr.NotToRs,
- OriginHosts: fltr.OriginHosts,
- NotOriginHosts: fltr.NotOriginHosts,
- Sources: fltr.Sources,
- NotSources: fltr.NotSources,
- RequestTypes: fltr.RequestTypes,
- NotRequestTypes: fltr.NotRequestTypes,
- Tenants: fltr.Tenants,
- NotTenants: fltr.NotTenants,
- Categories: fltr.Categories,
- NotCategories: fltr.NotCategories,
- Accounts: fltr.Accounts,
- NotAccounts: fltr.NotAccounts,
- Subjects: fltr.Subjects,
- NotSubjects: fltr.NotSubjects,
- DestinationPrefixes: fltr.DestinationPrefixes,
- NotDestinationPrefixes: fltr.NotDestinationPrefixes,
- Costs: fltr.Costs,
- NotCosts: fltr.NotCosts,
- ExtraFields: fltr.ExtraFields,
- NotExtraFields: fltr.NotExtraFields,
- MinUsage: fltr.MinUsage,
- MaxUsage: fltr.MaxUsage,
- Paginator: fltr.Paginator,
- OrderBy: fltr.OrderBy,
- }
- if len(fltr.SetupTimeStart) != 0 {
- var sTimeStart time.Time
- if sTimeStart, err = ParseTimeDetectLayout(fltr.SetupTimeStart, timezone); err != nil {
- return
- }
- cdrFltr.SetupTimeStart = TimePointer(sTimeStart)
- }
- if len(fltr.SetupTimeEnd) != 0 {
- var sTimeEnd time.Time
- if sTimeEnd, err = ParseTimeDetectLayout(fltr.SetupTimeEnd, timezone); err != nil {
- return
- }
- cdrFltr.SetupTimeEnd = TimePointer(sTimeEnd)
- }
- if len(fltr.AnswerTimeStart) != 0 {
- var aTimeStart time.Time
- if aTimeStart, err = ParseTimeDetectLayout(fltr.AnswerTimeStart, timezone); err != nil {
- return
- }
- cdrFltr.AnswerTimeStart = TimePointer(aTimeStart)
- }
- if len(fltr.AnswerTimeEnd) != 0 {
- var aTimeEnd time.Time
- if aTimeEnd, err = ParseTimeDetectLayout(fltr.AnswerTimeEnd, timezone); err != nil {
- return
- }
- cdrFltr.AnswerTimeEnd = TimePointer(aTimeEnd)
- }
- if len(fltr.CreatedAtStart) != 0 {
- var tStart time.Time
- if tStart, err = ParseTimeDetectLayout(fltr.CreatedAtStart, timezone); err != nil {
- return
- }
- cdrFltr.CreatedAtStart = TimePointer(tStart)
- }
- if len(fltr.CreatedAtEnd) != 0 {
- var tEnd time.Time
- if tEnd, err = ParseTimeDetectLayout(fltr.CreatedAtEnd, timezone); err != nil {
- return
- }
- cdrFltr.CreatedAtEnd = TimePointer(tEnd)
- }
- if len(fltr.UpdatedAtStart) != 0 {
- var tStart time.Time
- if tStart, err = ParseTimeDetectLayout(fltr.UpdatedAtStart, timezone); err != nil {
- return
- }
- cdrFltr.UpdatedAtStart = TimePointer(tStart)
- }
- if len(fltr.UpdatedAtEnd) != 0 {
- var tEnd time.Time
- if tEnd, err = ParseTimeDetectLayout(fltr.UpdatedAtEnd, timezone); err != nil {
- return
- }
- cdrFltr.UpdatedAtEnd = TimePointer(tEnd)
- }
- if oIDstart, has := fltr.ExtraArgs[OrderIDStart]; has {
- var oID int64
- if oID, err = IfaceAsTInt64(oIDstart); err != nil {
- return
- }
- cdrFltr.OrderIDStart = Int64Pointer(oID)
- }
- if oIDend, has := fltr.ExtraArgs[OrderIDEnd]; has {
- var oID int64
- if oID, err = IfaceAsTInt64(oIDend); err != nil {
- return
- }
- cdrFltr.OrderIDEnd = Int64Pointer(oID)
- }
- if mcost, has := fltr.ExtraArgs[MinCost]; has {
- var mc float64
- if mc, err = IfaceAsFloat64(mcost); err != nil {
- return
- }
- cdrFltr.MinCost = Float64Pointer(mc)
- }
- if mcost, has := fltr.ExtraArgs[MaxCost]; has {
- var mc float64
- if mc, err = IfaceAsFloat64(mcost); err != nil {
- return
- }
- cdrFltr.MaxCost = Float64Pointer(mc)
- }
- return
-}
-
-type AttrSetActions struct {
- ActionsId string // Actions id
- Overwrite bool // If previously defined, will be overwritten
- Actions []*TPAction // Set of actions this Actions profile will perform
-}
-
-type AttrExecuteAction struct {
- Tenant string
- Account string
- ActionsId string
-}
-
-type AttrSetAccount struct {
- Tenant string
- Account string
- ActionPlanID string
- ActionTriggersID string
- ExtraOptions map[string]bool
- ReloadScheduler bool
-}
-
-type AttrRemoveAccount struct {
- Tenant string
- Account string
- ReloadScheduler bool
-}
-
-type AttrGetCallCost struct {
- CgrId string // Unique id of the CDR
- RunId string // Run Id
-}
-
-type AttrSetBalance struct {
- Tenant string
- Account string
- BalanceType string
- Value float64
- Balance map[string]any
- ActionExtraData *map[string]any
- Cdrlog bool
-}
-
-// TPResourceProfile is used in APIs to manage remotely offline ResourceProfile
-type TPResourceProfile struct {
- TPid string
- Tenant string
- ID string // Identifier of this limit
- FilterIDs []string
- ActivationInterval *TPActivationInterval // Time when this limit becomes active/expires
- UsageTTL string
- Limit string // Limit value
- AllocationMessage string
- Blocker bool // blocker flag to stop processing on filters matched
- Stored bool
- Weight float64 // Weight to sort the ResourceLimits
- ThresholdIDs []string // Thresholds to check after changing Limit
-}
-
-// TPActivationInterval represents an activation interval for an item
-type TPActivationInterval struct {
- ActivationTime string
- ExpiryTime string
-}
-
-type ArgRSv1ResourceUsage struct {
- *CGREvent
- UsageID string // ResourceUsage Identifier
- UsageTTL *time.Duration
- Units float64
- *ArgDispatcher
-}
-
-type ArgsComputeFilterIndexIDs struct {
- Tenant string
- Context string
- AttributeIDs []string
- ResourceIDs []string
- StatIDs []string
- SupplierIDs []string
- ThresholdIDs []string
- ChargerIDs []string
- DispatcherIDs []string
-}
-
-type ArgsComputeFilterIndexes struct {
- Tenant string
- Context string
- AttributeS bool
- ResourceS bool
- StatS bool
- SupplierS bool
- ThresholdS bool
- ChargerS bool
- DispatcherS bool
-}
-
-// AsActivationTime converts TPActivationInterval into ActivationInterval
-func (tpAI *TPActivationInterval) AsActivationInterval(timezone string) (ai *ActivationInterval, err error) {
- var at, et time.Time
- if at, err = ParseTimeDetectLayout(tpAI.ActivationTime, timezone); err != nil {
- return
- }
- if et, err = ParseTimeDetectLayout(tpAI.ExpiryTime, timezone); err != nil {
- return
- }
- return &ActivationInterval{ActivationTime: at, ExpiryTime: et}, nil
-}
-
-type ActivationInterval struct {
- ActivationTime time.Time
- ExpiryTime time.Time
-}
-
-func (ai *ActivationInterval) IsActiveAtTime(atTime time.Time) bool {
- return (ai.ActivationTime.IsZero() || ai.ActivationTime.Before(atTime)) &&
- (ai.ExpiryTime.IsZero() || ai.ExpiryTime.After(atTime))
-}
-
-// Attributes to send on SessionDisconnect by SMG
-type AttrDisconnectSession struct {
- EventStart map[string]any
- Reason string
-}
-
-// MetricWithFilters is used in TPStatProfile
-type MetricWithFilters struct {
- FilterIDs []string
- MetricID string
-}
-
-// TPStatProfile is used in APIs to manage remotely offline StatProfile
-type TPStatProfile struct {
- TPid string
- Tenant string
- ID string
- FilterIDs []string
- ActivationInterval *TPActivationInterval
- QueueLength int
- TTL string
- Metrics []*MetricWithFilters
- Blocker bool // blocker flag to stop processing on filters matched
- Stored bool
- Weight float64
- MinItems int
- ThresholdIDs []string
-}
-
-// TPThresholdProfile is used in APIs to manage remotely offline ThresholdProfile
-type TPThresholdProfile struct {
- TPid string
- Tenant string
- ID string
- FilterIDs []string
- ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires
- MaxHits int
- MinHits int
- MinSleep string
- Blocker bool // blocker flag to stop processing on filters matched
- Weight float64 // Weight to sort the thresholds
- ActionIDs []string
- Async bool
-}
-
-// TPFilterProfile is used in APIs to manage remotely offline FilterProfile
-type TPFilterProfile struct {
- TPid string
- Tenant string
- ID string
- Filters []*TPFilter
- ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires
-}
-
-// TPFilter is used in TPFilterProfile
-type TPFilter struct {
- Type string // Filter type (*string, *timing, *rsr_filters, *cdr_stats)
- Element string // Name of the field providing us the Values to check (used in case of some )
- 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
-}
-
-// TPSupplierProfile is used in APIs to manage remotely offline SupplierProfile
-type TPSupplierProfile struct {
- TPid string
- Tenant string
- ID string
- FilterIDs []string
- ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires
- Sorting string
- SortingParameters []string
- Suppliers []*TPSupplier
- Weight float64
-}
-
-// TPAttribute is used in TPAttributeProfile
-type TPAttribute struct {
- FilterIDs []string
- Path string
- Type string
- Value string
-}
-
-// TPAttributeProfile is used in APIs to manage remotely offline AttributeProfile
-type TPAttributeProfile struct {
- TPid string
- Tenant string
- ID string
- FilterIDs []string
- ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires
- Contexts []string // bind this TPAttribute to multiple context
- Attributes []*TPAttribute
- Blocker bool
- Weight float64
-}
-
-// TPChargerProfile is used in APIs to manage remotely offline ChargerProfile
-type TPChargerProfile struct {
- TPid string
- Tenant string
- ID string
- FilterIDs []string
- ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires
- RunID string
- AttributeIDs []string
- Weight float64
-}
-
-type TPTntID struct {
- TPid string
- Tenant string
- ID string
-}
-
-// TPDispatcherProfile is used in APIs to manage remotely offline DispatcherProfile
-type TPDispatcherProfile struct {
- TPid string
- Tenant string
- ID string
- Subsystems []string
- FilterIDs []string
- ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires
- Strategy string
- StrategyParams []any // ie for distribution, set here the pool weights
- Weight float64
- Hosts []*TPDispatcherHostProfile
-}
-
-// TPDispatcherHostProfile is used in TPDispatcherProfile
-type TPDispatcherHostProfile struct {
- ID string
- FilterIDs []string
- Weight float64 // applied in case of multiple connections need to be ordered
- Params []any // additional parameters stored for a session
- Blocker bool // no connection after this one
-}
-
-// TPDispatcherHost is used in APIs to manage remotely offline DispatcherHost
-type TPDispatcherHost struct {
- TPid string
- Tenant string
- ID string
- Conns []*TPDispatcherHostConn
-}
-
-// TPDispatcherHostConn is used in TPDispatcherHost
-type TPDispatcherHostConn struct {
- Address string
- Transport string
- TLS bool
-}
-
-type UsageInterval struct {
- Min *time.Duration
- Max *time.Duration
-}
-
-type TimeInterval struct {
- Begin *time.Time
- End *time.Time
-}
-
-type AttrRemoteLock struct {
- ReferenceID string // reference ID for this lock if available
- LockIDs []string // List of IDs to obtain lock for
- Timeout time.Duration // Automatically unlock on timeout
-}
-
-type SMCostFilter struct { //id cu litere mare
- CGRIDs []string
- NotCGRIDs []string
- RunIDs []string
- NotRunIDs []string
- OriginHosts []string
- NotOriginHosts []string
- OriginIDs []string
- NotOriginIDs []string
- CostSources []string
- NotCostSources []string
- Usage UsageInterval
- CreatedAt TimeInterval
-}
-
-func AppendToSMCostFilter(smcFilter *SMCostFilter, fieldType, fieldName string,
- values []string, timezone string) (smcf *SMCostFilter, err error) {
- switch fieldName {
- case DynamicDataPrefix + CGRID:
- switch fieldType {
- case MetaString:
- smcFilter.CGRIDs = append(smcFilter.CGRIDs, values...)
- case MetaNotString:
- smcFilter.NotCGRIDs = append(smcFilter.NotCGRIDs, values...)
- default:
- err = fmt.Errorf("FilterType: %q not supported for FieldName: %q", fieldType, fieldName)
- }
- case DynamicDataPrefix + RunID:
- switch fieldType {
- case MetaString:
- smcFilter.RunIDs = append(smcFilter.RunIDs, values...)
- case MetaNotString:
- smcFilter.NotRunIDs = append(smcFilter.NotRunIDs, values...)
- default:
- err = fmt.Errorf("FilterType: %q not supported for FieldName: %q", fieldType, fieldName)
- }
- case DynamicDataPrefix + OriginHost:
- switch fieldType {
- case MetaString:
- smcFilter.OriginHosts = append(smcFilter.OriginHosts, values...)
- case MetaNotString:
- smcFilter.NotOriginHosts = append(smcFilter.NotOriginHosts, values...)
- default:
- err = fmt.Errorf("FilterType: %q not supported for FieldName: %q", fieldType, fieldName)
- }
- case DynamicDataPrefix + OriginID:
- switch fieldType {
- case MetaString:
- smcFilter.OriginIDs = append(smcFilter.OriginIDs, values...)
- case MetaNotString:
- smcFilter.NotOriginIDs = append(smcFilter.NotOriginIDs, values...)
- default:
- err = fmt.Errorf("FilterType: %q not supported for FieldName: %q", fieldType, fieldName)
- }
- case DynamicDataPrefix + CostSource:
- switch fieldType {
- case MetaString:
- smcFilter.CostSources = append(smcFilter.CostSources, values...)
- case MetaNotString:
- smcFilter.NotCostSources = append(smcFilter.NotCostSources, values...)
- default:
- err = fmt.Errorf("FilterType: %q not supported for FieldName: %q", fieldType, fieldName)
- }
- case DynamicDataPrefix + Usage:
- switch fieldType {
- case MetaGreaterOrEqual:
- var minUsage time.Duration
- minUsage, err = ParseDurationWithNanosecs(values[0])
- if err != nil {
- err = fmt.Errorf("Error when converting field: %q value: %q in time.Duration ", fieldType, fieldName)
- break
- }
- smcFilter.Usage.Min = &minUsage
- case MetaLessThan:
- var maxUsage time.Duration
- maxUsage, err = ParseDurationWithNanosecs(values[0])
- if err != nil {
- err = fmt.Errorf("Error when converting field: %q value: %q in time.Duration ", fieldType, fieldName)
- break
- }
- smcFilter.Usage.Max = &maxUsage
- default:
- err = fmt.Errorf("FilterType: %q not supported for FieldName: %q", fieldType, fieldName)
- }
- case DynamicDataPrefix + CreatedAt:
- switch fieldType {
- case MetaGreaterOrEqual:
- var start time.Time
- start, err = ParseTimeDetectLayout(values[0], timezone)
- if err != nil {
- err = fmt.Errorf("Error when converting field: %q value: %q in time.Time ", fieldType, fieldName)
- break
- }
- if !start.IsZero() {
- smcFilter.CreatedAt.Begin = &start
- }
- case MetaLessThan:
- var end time.Time
- end, err = ParseTimeDetectLayout(values[0], timezone)
- if err != nil {
- err = fmt.Errorf("Error when converting field: %q value: %q in time.Time ", fieldType, fieldName)
- break
- }
- if !end.IsZero() {
- smcFilter.CreatedAt.End = &end
- }
- default:
- err = fmt.Errorf("FilterType: %q not supported for FieldName: %q", fieldType, fieldName)
- }
- default:
- err = fmt.Errorf("FieldName: %q not supported", fieldName)
- }
- return smcFilter, err
-}
-
-type RPCCDRsFilterWithArgDispatcher struct {
- *RPCCDRsFilter
- *ArgDispatcher
- *TenantArg
-}
-
-type ArgsGetCacheItemIDsWithArgDispatcher struct {
- *ArgDispatcher
- TenantArg
- ArgsGetCacheItemIDs
-}
-
-type ArgsGetCacheItemWithArgDispatcher struct {
- *ArgDispatcher
- TenantArg
- ArgsGetCacheItem
-}
-
-type AttrReloadCacheWithArgDispatcher struct {
- *ArgDispatcher
- TenantArg
- AttrReloadCache
-}
-
-type AttrCacheIDsWithArgDispatcher struct {
- *ArgDispatcher
- TenantArg
- CacheIDs []string
-}
-
-type ArgsGetGroupWithArgDispatcher struct {
- *ArgDispatcher
- TenantArg
- ArgsGetGroup
-}
-
-type ArgsGetCacheItemIDs struct {
- CacheID string
- ItemIDPrefix string
-}
-
-type ArgsGetCacheItem struct {
- CacheID string
- ItemID string
-}
-
-type ArgsGetGroup struct {
- CacheID string
- GroupID string
-}
-
-type SessionFilter struct {
- Limit *int
- Filters []string
- Tenant string
- *ArgDispatcher
-}
-
-type ArgDispatcher struct {
- APIKey *string
- RouteID *string
-}
-
-type RatingPlanCostArg struct {
- RatingPlanIDs []string
- Destination string
- SetupTime string
- Usage string
- *ArgDispatcher
-}
-
-type GetCostOnRatingPlansArgs struct {
- Account string
- Subject string
- Destination string
- Tenant string
- SetupTime time.Time
- Usage time.Duration
- RatingPlanIDs []string
- *ArgDispatcher
-}
-
-type GetMaxSessionTimeOnAccountsArgs struct {
- Subject string
- Destination string
- Tenant string
- SetupTime time.Time
- Usage time.Duration
- AccountIDs []string
- *ArgDispatcher
-}
-
-type DurationArgs struct {
- DurationTime time.Duration
-}
-
-
-
/*
-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 utils
-
-import (
- "encoding/base64"
- "fmt"
- "net/http"
- "strings"
-)
-
-// use provides a cleaner interface for chaining middleware for single routes.
-// Middleware functions are simple HTTP handlers (w http.ResponseWriter, r *http.Request)
-//
-// r.HandleFunc("/login", use(loginHandler, rateLimit, csrf))
-// r.HandleFunc("/form", use(formHandler, csrf))
-// r.HandleFunc("/about", aboutHandler)
-//
-// From https://gist.github.com/elithrar/9146306
-// See https://gist.github.com/elithrar/7600878#comment-955958 for how to extend it to suit simple http.Handler's
-func use(h http.HandlerFunc, middleware ...func(http.HandlerFunc) http.HandlerFunc) http.HandlerFunc {
- for _, m := range middleware {
- h = m(h)
- }
-
- return h
-}
-
-type basicAuthMiddleware func(h http.HandlerFunc) http.HandlerFunc
-
-// basicAuth returns a middleware function to intercept the request and validate
-func basicAuth(userList map[string]string) basicAuthMiddleware {
- return func(h http.HandlerFunc) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
-
- authHeader := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
- if len(authHeader) != 2 {
- Logger.Warning("<BasicAuth> Missing authorization header value")
- http.Error(w, "Not authorized", http.StatusUnauthorized)
- return
- }
-
- authHeaderDecoded, err := base64.StdEncoding.DecodeString(authHeader[1])
- if err != nil {
- Logger.Warning("<BasicAuth> Unable to decode authorization header")
- http.Error(w, err.Error(), http.StatusUnauthorized)
- return
- }
-
- userPass := strings.SplitN(string(authHeaderDecoded), ":", 2)
- if len(userPass) != 2 {
- Logger.Warning("<BasicAuth> Unauthorized API access. Missing or extra credential components")
- http.Error(w, "Not authorized", http.StatusUnauthorized)
- return
- }
-
- valid := verifyCredential(userPass[0], userPass[1], userList)
- if !valid {
- Logger.Warning(fmt.Sprintf("<BasicAuth> Unauthorized API access by user '%s'", userPass[0]))
- http.Error(w, "Not authorized", http.StatusUnauthorized)
- return
- }
-
- h.ServeHTTP(w, r)
- }
- }
-}
-
-// verifyCredential validates the incoming username and password against the authorized user list
-func verifyCredential(username string, password string, userList map[string]string) bool {
- hash, ok := userList[username]
- if !ok {
- return false
- }
-
- storedPass, err := base64.StdEncoding.DecodeString(hash)
- if err != nil {
- return false
- }
-
- return string(storedPass[:]) == password
-}
-
-
-
/*
-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 utils
-
-import (
- "net"
-
- "github.com/cenkalti/rpc2"
- rpc2_jsonrpc "github.com/cenkalti/rpc2/jsonrpc"
- "github.com/cgrates/birpc"
- "github.com/cgrates/birpc/context"
-)
-
-// NewBiJSONrpcClient will create a bidirectional JSON client connection
-func NewBiJSONrpcClient(addr string, handlers map[string]any) (*rpc2.Client, error) {
- conn, err := net.Dial(TCP, addr)
- if err != nil {
- return nil, err
- }
- clnt := rpc2.NewClientWithCodec(rpc2_jsonrpc.NewJSONCodec(conn))
- for method, handlerFunc := range handlers {
- clnt.Handle(method, handlerFunc)
- }
- go clnt.Run()
- return clnt, nil
-}
-
-// Interface which the server needs to work as BiRPCServer
-type BiRPCServer interface {
- Call(*context.Context, string, any, any) error // So we can use it also as birpc.ClientConnector
- CallBiRPC(birpc.ClientConnector, string, any, any) error
-}
-
-type BiRPCClient interface {
- Call(*context.Context, string, any, any) error // So we can use it also as birpc.ClientConnector
- ID() string
-}
-
-func NewBiRPCInternalClient(serverConn BiRPCServer) *BiRPCInternalClient {
- return &BiRPCInternalClient{serverConn: serverConn}
-}
-
-// Need separate client from the original RpcClientConnection since diretly passing the server is not enough without passing the client's reference
-type BiRPCInternalClient struct {
- serverConn BiRPCServer
- clntConn birpc.ClientConnector // conn to reach client and do calls over it
-}
-
-// Used in case when clientConn is not available at init time (eg: SMGAsterisk who needs the biRPCConn at initialization)
-func (clnt *BiRPCInternalClient) SetClientConn(clntConn birpc.ClientConnector) {
- clnt.clntConn = clntConn
-}
-
-// Part of birpc.ClientConnector interface
-func (clnt *BiRPCInternalClient) Call(ctx *context.Context, serviceMethod string, args any, reply any) error {
- return clnt.serverConn.CallBiRPC(clnt.clntConn, serviceMethod, args, reply)
-}
-
-
-
/*
-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 utils
-
-import (
- "time"
-)
-
-// CGREvent is a generic event processed by CGR services
-type CGREvent struct {
- Tenant string
- ID string
- Time *time.Time // event time
- Event map[string]any
-}
-
-func (ev *CGREvent) HasField(fldName string) (has bool) {
- _, has = ev.Event[fldName]
- return
-}
-
-func (ev *CGREvent) CheckMandatoryFields(fldNames []string) error {
- for _, fldName := range fldNames {
- if _, has := ev.Event[fldName]; !has {
- return NewErrMandatoryIeMissing(fldName)
- }
- }
- return nil
-}
-
-// FieldAsString returns a field as string instance
-func (ev *CGREvent) FieldAsString(fldName string) (val string, err error) {
- iface, has := ev.Event[fldName]
- if !has {
- return "", ErrNotFound
- }
- return IfaceAsString(iface), nil
-}
-
-// FieldAsTime returns a field as Time instance
-func (ev *CGREvent) FieldAsTime(fldName string, timezone string) (t time.Time, err error) {
- iface, has := ev.Event[fldName]
- if !has {
- err = ErrNotFound
- return
- }
- return IfaceAsTime(iface, timezone)
-}
-
-// FieldAsDuration returns a field as Duration instance
-func (ev *CGREvent) FieldAsDuration(fldName string) (d time.Duration, err error) {
- iface, has := ev.Event[fldName]
- if !has {
- err = ErrNotFound
- return
- }
- return IfaceAsDuration(iface)
-}
-
-// FieldAsFloat64 returns a field as float64 instance
-func (ev *CGREvent) FieldAsFloat64(fldName string) (f float64, err error) {
- iface, has := ev.Event[fldName]
- if !has {
- return f, ErrNotFound
- }
- return IfaceAsFloat64(iface)
-}
-
-func (ev *CGREvent) TenantID() string {
- return ConcatenatedKey(ev.Tenant, ev.ID)
-}
-
-/*
-func (ev *CGREvent) FilterableEvent(fltredFields []string) (fEv map[string]any) {
- fEv = make(map[string]any)
- if len(fltredFields) == 0 {
- i := 0
- fltredFields = make([]string, len(ev.Event))
- for k := range ev.Event {
- fltredFields[i] = k
- i++
- }
- }
- for _, fltrFld := range fltredFields {
- fldVal, has := ev.Event[fltrFld]
- if !has {
- continue // the field does not exist in map, ignore it
- }
- valOf := reflect.ValueOf(fldVal)
- if valOf.Kind() == reflect.String {
- fEv[fltrFld] = StringToInterface(valOf.String()) // attempt converting from string to comparable interface
- } else {
- fEv[fltrFld] = fldVal
- }
- }
- return
-}
-*/
-
-func (ev *CGREvent) Clone() (clned *CGREvent) {
- clned = &CGREvent{
- Tenant: ev.Tenant,
- ID: ev.ID,
- Event: make(map[string]any),
- }
- if ev.Time != nil {
- clned.Time = TimePointer(*ev.Time)
- }
- for k, v := range ev.Event {
- clned.Event[k] = v
- }
- return
-}
-
-func (ev *CGREvent) consumeArgDispatcher() (arg *ArgDispatcher) {
- if ev == nil {
- return
- }
- //check if we have APIKey in event and in case it has add it in ArgDispatcher
- apiKeyIface, hasApiKey := ev.Event[MetaApiKey]
- if hasApiKey {
- delete(ev.Event, MetaApiKey)
- arg = &ArgDispatcher{
- APIKey: StringPointer(apiKeyIface.(string)),
- }
- }
- //check if we have RouteID in event and in case it has add it in ArgDispatcher
- routeIDIface, hasRouteID := ev.Event[MetaRouteID]
- if !hasRouteID {
- return
- }
- delete(ev.Event, MetaRouteID)
- if !hasApiKey { //in case we don't have APIKey, but we have RouteID we need to initialize the struct
- return &ArgDispatcher{
- RouteID: StringPointer(routeIDIface.(string)),
- }
- }
- arg.RouteID = StringPointer(routeIDIface.(string))
- return
-}
-
-// ConsumeSupplierPaginator will consume supplierPaginator if presented
-func (ev *CGREvent) consumeSupplierPaginator() (args *Paginator) {
- args = new(Paginator)
- if ev == nil {
- return
- }
- //check if we have suppliersLimit in event and in case it has add it in args
- limitIface, hasSuppliersLimit := ev.Event[MetaSuppliersLimit]
- if hasSuppliersLimit {
- delete(ev.Event, MetaSuppliersLimit)
- limit, err := IfaceAsInt64(limitIface)
- if err != nil {
- Logger.Err(err.Error())
- return
- }
- args = &Paginator{
- Limit: IntPointer(int(limit)),
- }
- }
- //check if we have offset in event and in case it has add it in args
- offsetIface, hasSuppliersOffset := ev.Event[MetaSuppliersOffset]
- if hasSuppliersOffset {
- delete(ev.Event, MetaSuppliersOffset)
- offset, err := IfaceAsInt64(offsetIface)
- if err != nil {
- Logger.Err(err.Error())
- return
- }
- if !hasSuppliersLimit { //in case we don't have limit, but we have offset we need to initialize the struct
- args = &Paginator{
- Offset: IntPointer(int(offset)),
- }
- } else {
- args.Offset = IntPointer(int(offset))
- }
- }
- return
-}
-
-// ExtractedArgs stores the extracted arguments from CGREvent
-type ExtractedArgs struct {
- ArgDispatcher *ArgDispatcher
- SupplierPaginator *Paginator
-}
-
-// ExtractArgs extracts the ArgDispatcher and SupplierPaginator from the received event
-func (ev *CGREvent) ExtractArgs(dispatcherFlag, consumeSupplierPaginator bool) (ca ExtractedArgs) {
- ca = ExtractedArgs{
- ArgDispatcher: ev.consumeArgDispatcher(),
- }
- if dispatcherFlag && ca.ArgDispatcher == nil {
- ca.ArgDispatcher = new(ArgDispatcher)
- }
- if consumeSupplierPaginator {
- ca.SupplierPaginator = ev.consumeSupplierPaginator()
- }
- return
-}
-
-// CGREvents is a group of generic events processed by CGR services
-// ie: derived CDRs
-type CGREvents struct {
- Tenant string
- ID string
- Time *time.Time // event time
- Events []map[string]any
-}
-
-func NewCGREventWithArgDispatcher() *CGREventWithArgDispatcher {
- return &CGREventWithArgDispatcher{
- CGREvent: new(CGREvent),
- ArgDispatcher: new(ArgDispatcher),
- }
-}
-
-type CGREventWithArgDispatcher struct {
- *CGREvent
- *ArgDispatcher
-}
-
-func (ev *CGREventWithArgDispatcher) Clone() (clned *CGREventWithArgDispatcher) {
- if ev == nil {
- return
- }
- clned = new(CGREventWithArgDispatcher)
- if ev.CGREvent != nil {
- clned.CGREvent = ev.CGREvent.Clone()
- }
- if ev.ArgDispatcher != nil {
- clned.ArgDispatcher = new(ArgDispatcher)
- *clned.ArgDispatcher = *ev.ArgDispatcher
- }
- return
-}
-
-
-
/*
-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 utils
-
-import (
- "io"
-)
-
-// CgrRecordWriter is a writer for one line, compatible with csv.Writer interface on Write
-// Used in TP exporter
-type CgrRecordWriter interface {
- Write([]string) error
- Flush()
-}
-
-// NewCgrIORecordWriter return CgrRecordWriter that will replace csv.Writer
-func NewCgrIORecordWriter(w io.Writer) *CgrIORecordWriter {
- return &CgrIORecordWriter{w: w}
-}
-
-// CgrIORecordWriter implements CgrRecordWriter
-type CgrIORecordWriter struct {
- w io.Writer
-}
-
-// Write into the Writer the record
-func (rw *CgrIORecordWriter) Write(record []string) error {
- for _, fld := range append(record, "\n") { // Postpend the new line char and write record in the writer
- if _, err := io.WriteString(rw.w, fld); err != nil {
- return err
- }
- }
- return nil
-}
-
-// Flush only to implement CgrRecordWriter
-// ToDo: make sure we properly handle this method
-func (*CgrIORecordWriter) Flush() {
- return
-}
-
-
-
/*
-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 utils
-
-import (
- "fmt"
-)
-
-var ConReqs *ConcReqs
-
-type ConcReqs struct {
- limit int
- strategy string
- aReqs chan struct{}
-}
-
-func NewConReqs(reqs int, strategy string) *ConcReqs {
- cR := &ConcReqs{
- limit: reqs,
- strategy: strategy,
- aReqs: make(chan struct{}, reqs),
- }
- for i := 0; i < reqs; i++ {
- cR.aReqs <- struct{}{}
- }
- return cR
-}
-
-var errDeny = fmt.Errorf("denying request due to maximum active requests reached")
-
-func (cR *ConcReqs) Allocate() (err error) {
- if cR.limit == 0 {
- return
- }
- switch cR.strategy {
- case MetaBusy:
- if len(cR.aReqs) == 0 {
- return errDeny
- }
- fallthrough
- case MetaQueue:
- <-cR.aReqs // get from channel
- }
- return
-}
-
-func (cR *ConcReqs) Deallocate() {
- if cR.limit == 0 {
- return
- }
- cR.aReqs <- struct{}{}
-}
-
-
-
/*
-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/>
-*/
-
-// Most of the logic follows standard library implementation in this file
-package utils
-
-import (
- "bufio"
- "encoding/gob"
- "io"
- "log"
- "net/rpc"
-)
-
-type concReqsGobServerCodec struct {
- rwc io.ReadWriteCloser
- dec *gob.Decoder
- enc *gob.Encoder
- encBuf *bufio.Writer
- closed bool
- allocated bool // populated if we have allocated a channel for concurrent requests
-}
-
-func NewConcReqsGobServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
- buf := bufio.NewWriter(conn)
- return &concReqsGobServerCodec{
- rwc: conn,
- dec: gob.NewDecoder(conn),
- enc: gob.NewEncoder(buf),
- encBuf: buf,
- }
-}
-
-func (c *concReqsGobServerCodec) ReadRequestHeader(r *rpc.Request) error {
- return c.dec.Decode(r)
-}
-
-func (c *concReqsGobServerCodec) ReadRequestBody(body any) error {
- if err := ConReqs.Allocate(); err != nil {
- return err
- }
- c.allocated = true
- return c.dec.Decode(body)
-}
-
-func (c *concReqsGobServerCodec) WriteResponse(r *rpc.Response, body any) (err error) {
- if c.allocated {
- defer func() {
- ConReqs.Deallocate()
- c.allocated = false
- }()
- }
- if err = c.enc.Encode(r); err != nil {
- if c.encBuf.Flush() == nil {
- // Gob couldn't encode the header. Should not happen, so if it does,
- // shut down the connection to signal that the connection is broken.
- log.Println("rpc: gob error encoding response:", err)
- c.Close()
- }
- return
- }
- if err = c.enc.Encode(body); err != nil {
- if c.encBuf.Flush() == nil {
- // Was a gob problem encoding the body but the header has been written.
- // Shut down the connection to signal that the connection is broken.
- log.Println("rpc: gob error encoding body:", err)
- c.Close()
- }
- return
- }
- return c.encBuf.Flush()
-}
-
-func (c *concReqsGobServerCodec) Close() error {
- if c.closed {
- // Only call c.rwc.Close once; otherwise the semantics are undefined.
- return nil
- }
- c.closed = true
- return c.rwc.Close()
-}
-
-
-
/*
-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/>
-*/
-
-// Most of the logic follows standard library implementation in this file
-package utils
-
-import (
- "encoding/json"
- "errors"
- "io"
- "net/rpc"
- "sync"
-)
-
-type concReqsServerCodec struct {
- dec *json.Decoder // for reading JSON values
- enc *json.Encoder // for writing JSON values
- c io.Closer
-
- // temporary work space
- req serverRequest
-
- // JSON-RPC clients can use arbitrary json values as request IDs.
- // Package rpc expects uint64 request IDs.
- // We assign uint64 sequence numbers to incoming requests
- // but save the original request ID in the pending map.
- // When rpc responds, we use the sequence number in
- // the response to find the original request ID.
- mutex sync.Mutex // protects seq, pending
- seq uint64
- pending map[uint64]*json.RawMessage
-
- allocated bool // populated if we have allocated a channel for concurrent requests
-}
-
-// NewConcReqsServerCodec returns a new rpc.ServerCodec using JSON-RPC on conn.
-func NewConcReqsServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
- return &concReqsServerCodec{
- dec: json.NewDecoder(conn),
- enc: json.NewEncoder(conn),
- c: conn,
- pending: make(map[uint64]*json.RawMessage),
- }
-}
-
-func (c *concReqsServerCodec) ReadRequestHeader(r *rpc.Request) error {
- c.req.reset()
- if err := c.dec.Decode(&c.req); err != nil {
- return err
- }
- r.ServiceMethod = c.req.Method
-
- // JSON request id can be any JSON value;
- // RPC package expects uint64. Translate to
- // internal uint64 and save JSON on the side.
- c.mutex.Lock()
- c.seq++
- c.pending[c.seq] = c.req.Id
- c.req.Id = nil
- r.Seq = c.seq
- c.mutex.Unlock()
-
- return nil
-}
-
-func (c *concReqsServerCodec) ReadRequestBody(x any) error {
- if err := ConReqs.Allocate(); err != nil {
- return err
- }
- c.allocated = true
- if x == nil {
- return nil
- }
- if c.req.Params == nil {
- return errMissingParams
- }
- // JSON params is array value.
- // RPC params is struct.
- // Unmarshal into array containing struct for now.
- // Should think about making RPC more general.
- var params [1]any
- params[0] = x
- return json.Unmarshal(*c.req.Params, ¶ms)
-}
-
-func (c *concReqsServerCodec) WriteResponse(r *rpc.Response, x any) error {
- if c.allocated {
- defer func() {
- ConReqs.Deallocate()
- c.allocated = false
- }()
- }
-
- c.mutex.Lock()
- b, ok := c.pending[r.Seq]
- if !ok {
- c.mutex.Unlock()
- return errors.New("invalid sequence number in response")
- }
- delete(c.pending, r.Seq)
- c.mutex.Unlock()
-
- if b == nil {
- // Invalid request so no id. Use JSON null.
- b = &null
- }
- resp := serverResponse{Id: b}
- if r.Error == "" {
- resp.Result = x
- } else {
- resp.Error = r.Error
- }
- return c.enc.Encode(resp)
-}
-
-func (c *concReqsServerCodec) Close() error {
- return c.c.Close()
-}
-
-
-
/*
-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 utils
-
-import "time"
-
-var (
- CDRExportFormats = NewStringSet([]string{DRYRUN, MetaFileCSV, MetaFileFWV, MetaHTTPjsonCDR, MetaHTTPjsonMap,
- MetaHTTPjson, MetaHTTPPost, MetaAMQPjsonCDR, MetaAMQPjsonMap, MetaAMQPV1jsonMap, MetaSQSjsonMap,
- MetaKafkajsonMap, MetaS3jsonMap})
- MainCDRFields = NewStringSet([]string{CGRID, Source, OriginHost, OriginID, ToR, RequestType, Tenant, Category,
- Account, Subject, Destination, SetupTime, AnswerTime, Usage, COST, RATED, Partial, RunID,
- PreRated, CostSource, CostDetails, ExtraInfo, OrderID})
- PostPaidRatedSlice = []string{META_POSTPAID, META_RATED}
- ItemList = NewStringSet([]string{MetaAccounts, MetaAttributes, MetaChargers, MetaDispatchers, MetaDispatcherHosts,
- MetaFilters, MetaResources, MetaStats, MetaThresholds, MetaSuppliers,
- })
- AttrInlineTypes = NewStringSet([]string{META_CONSTANT, MetaVariable, META_COMPOSED, META_USAGE_DIFFERENCE,
- MetaSum, MetaValueExponent})
-
- GitLastLog string // If set, it will be processed as part of versioning
- PosterTransportContentTypes = map[string]string{
- MetaHTTPjsonCDR: CONTENT_JSON,
- MetaHTTPjsonMap: CONTENT_JSON,
- MetaHTTPjson: CONTENT_JSON,
- MetaHTTPPost: CONTENT_FORM,
- MetaAMQPjsonCDR: CONTENT_JSON,
- MetaAMQPjsonMap: CONTENT_JSON,
- MetaAMQPV1jsonMap: CONTENT_JSON,
- MetaSQSjsonMap: CONTENT_JSON,
- MetaKafkajsonMap: CONTENT_JSON,
- MetaS3jsonMap: CONTENT_JSON,
- }
- CDREFileSuffixes = map[string]string{
- MetaHTTPjsonCDR: JSNSuffix,
- MetaHTTPjsonMap: JSNSuffix,
- MetaAMQPjsonCDR: JSNSuffix,
- MetaAMQPjsonMap: JSNSuffix,
- MetaAMQPV1jsonMap: JSNSuffix,
- MetaSQSjsonMap: JSNSuffix,
- MetaKafkajsonMap: JSNSuffix,
- MetaS3jsonMap: JSNSuffix,
- MetaHTTPPost: FormSuffix,
- MetaFileCSV: CSVSuffix,
- MetaFileFWV: FWVSuffix,
- }
- // CachePartitions enables creation of cache partitions
- CachePartitions = NewStringSet([]string{CacheDestinations, CacheReverseDestinations,
- CacheRatingPlans, CacheRatingProfiles, CacheActions, CacheActionPlans,
- CacheAccountActionPlans, CacheActionTriggers, CacheSharedGroups, CacheTimings,
- CacheResourceProfiles, CacheResources, CacheEventResources, CacheStatQueueProfiles,
- CacheStatQueues, CacheThresholdProfiles, CacheThresholds, CacheFilters,
- CacheSupplierProfiles, CacheAttributeProfiles, CacheChargerProfiles,
- CacheDispatcherProfiles, CacheDispatcherHosts, CacheResourceFilterIndexes,
- CacheStatFilterIndexes, CacheThresholdFilterIndexes, CacheSupplierFilterIndexes,
- CacheAttributeFilterIndexes, CacheChargerFilterIndexes, CacheDispatcherFilterIndexes, CacheReverseFilterIndexes,
- CacheDispatcherRoutes, CacheDiameterMessages, CacheRPCResponses, CacheClosedSessions,
- CacheCDRIDs, CacheLoadIDs, CacheRPCConnections, CacheRatingProfilesTmp})
- CacheInstanceToPrefix = map[string]string{
- CacheDestinations: DESTINATION_PREFIX,
- CacheReverseDestinations: REVERSE_DESTINATION_PREFIX,
- CacheRatingPlans: RATING_PLAN_PREFIX,
- CacheRatingProfiles: RATING_PROFILE_PREFIX,
- CacheActions: ACTION_PREFIX,
- CacheActionPlans: ACTION_PLAN_PREFIX,
- CacheAccountActionPlans: AccountActionPlansPrefix,
- CacheActionTriggers: ACTION_TRIGGER_PREFIX,
- CacheSharedGroups: SHARED_GROUP_PREFIX,
- CacheResourceProfiles: ResourceProfilesPrefix,
- CacheResources: ResourcesPrefix,
- CacheTimings: TimingsPrefix,
- CacheStatQueueProfiles: StatQueueProfilePrefix,
- CacheStatQueues: StatQueuePrefix,
- CacheThresholdProfiles: ThresholdProfilePrefix,
- CacheThresholds: ThresholdPrefix,
- CacheFilters: FilterPrefix,
- CacheSupplierProfiles: SupplierProfilePrefix,
- CacheAttributeProfiles: AttributeProfilePrefix,
- CacheChargerProfiles: ChargerProfilePrefix,
- CacheDispatcherProfiles: DispatcherProfilePrefix,
- CacheDispatcherHosts: DispatcherHostPrefix,
- CacheResourceFilterIndexes: ResourceFilterIndexes,
- CacheStatFilterIndexes: StatFilterIndexes,
- CacheThresholdFilterIndexes: ThresholdFilterIndexes,
- CacheSupplierFilterIndexes: SupplierFilterIndexes,
- CacheAttributeFilterIndexes: AttributeFilterIndexes,
- CacheChargerFilterIndexes: ChargerFilterIndexes,
- CacheDispatcherFilterIndexes: DispatcherFilterIndexes,
- CacheReverseFilterIndexes: ReverseFilterIndexes,
- CacheLoadIDs: LoadIDPrefix,
- CacheAccounts: ACCOUNT_PREFIX,
- }
- CachePrefixToInstance map[string]string // will be built on init
- PrefixToIndexCache = map[string]string{
- ThresholdProfilePrefix: CacheThresholdFilterIndexes,
- ResourceProfilesPrefix: CacheResourceFilterIndexes,
- StatQueueProfilePrefix: CacheStatFilterIndexes,
- SupplierProfilePrefix: CacheSupplierFilterIndexes,
- AttributeProfilePrefix: CacheAttributeFilterIndexes,
- ChargerProfilePrefix: CacheChargerFilterIndexes,
- DispatcherProfilePrefix: CacheDispatcherFilterIndexes,
- ReverseFilterIndexes: CacheReverseFilterIndexes,
- }
- CacheIndexesToPrefix map[string]string // will be built on init
-
- // NonMonetaryBalances are types of balances which are not handled as monetary
- NonMonetaryBalances = NewStringSet([]string{VOICE, SMS, DATA, GENERIC})
-
- // AccountableRequestTypes are the ones handled by Accounting subsystem
- AccountableRequestTypes = NewStringSet([]string{META_PREPAID, META_POSTPAID, META_PSEUDOPREPAID})
-
- CacheDataDBPartitions = NewStringSet([]string{CacheDestinations, CacheReverseDestinations,
- CacheRatingPlans, CacheRatingProfiles, CacheActions,
- CacheActionPlans, CacheAccountActionPlans, CacheActionTriggers, CacheSharedGroups, CacheResourceProfiles, CacheResources,
- CacheTimings, CacheStatQueueProfiles, CacheStatQueues, CacheThresholdProfiles, CacheThresholds,
- CacheFilters, CacheSupplierProfiles, CacheAttributeProfiles, CacheChargerProfiles,
- CacheDispatcherProfiles, CacheDispatcherHosts, CacheResourceFilterIndexes, CacheStatFilterIndexes,
- CacheThresholdFilterIndexes, CacheSupplierFilterIndexes, CacheAttributeFilterIndexes, CacheReverseFilterIndexes,
- CacheChargerFilterIndexes, CacheDispatcherFilterIndexes, CacheLoadIDs, CacheAccounts})
-
- // ProtectedSFlds are the fields that sessions should not alter
- ProtectedSFlds = NewStringSet([]string{CGRID, OriginHost, OriginID, Usage})
-)
-
-const (
- CGRateS = "CGRateS"
- VERSION = "v0.10.3~dev"
- DIAMETER_FIRMWARE_REVISION = 918
- REDIS_MAX_CONNS = 10
- CGRATES = "cgrates"
- POSTGRES = "postgres"
- MYSQL = "mysql"
- MONGO = "mongo"
- REDIS = "redis"
- INTERNAL = "internal"
- DataManager = "DataManager"
- LOCALHOST = "127.0.0.1"
- PREPAID = "prepaid"
- META_PREPAID = "*prepaid"
- POSTPAID = "postpaid"
- META_POSTPAID = "*postpaid"
- PSEUDOPREPAID = "pseudoprepaid"
- META_PSEUDOPREPAID = "*pseudoprepaid"
- META_RATED = "*rated"
- META_NONE = "*none"
- META_NOW = "*now"
- ROUNDING_UP = "*up"
- ROUNDING_MIDDLE = "*middle"
- ROUNDING_DOWN = "*down"
- ANY = "*any"
- MetaAll = "*all"
- ZERO = "*zero"
- ASAP = "*asap"
- COMMENT_CHAR = '#'
- CSV_SEP = ','
- FALLBACK_SEP = ';'
- INFIELD_SEP = ";"
- MetaPipe = "*|"
- FIELDS_SEP = ","
- InInFieldSep = ":"
- STATIC_HDRVAL_SEP = "::"
- REGEXP_PREFIX = "~"
- FILTER_VAL_START = "("
- FILTER_VAL_END = ")"
- JSON = "json"
- MSGPACK = "msgpack"
- CSV_LOAD = "CSVLOAD"
- CGRID = "CGRID"
- ToR = "ToR"
- OrderID = "OrderID"
- OriginID = "OriginID"
- InitialOriginID = "InitialOriginID"
- OriginIDPrefix = "OriginIDPrefix"
- Source = "Source"
- OriginHost = "OriginHost"
- RequestType = "RequestType"
- Direction = "Direction"
- Tenant = "Tenant"
- Category = "Category"
- Context = "Context"
- Contexts = "Contexts"
- Account = "Account"
- Subject = "Subject"
- Destination = "Destination"
- SetupTime = "SetupTime"
- AnswerTime = "AnswerTime"
- Usage = "Usage"
- Value = "Value"
- LastUsed = "LastUsed"
- PDD = "PDD"
- SUPPLIER = "Supplier"
- RunID = "RunID"
- MetaReqRunID = "*req.RunID"
- COST = "Cost"
- CostDetails = "CostDetails"
- RATED = "rated"
- Partial = "Partial"
- PreRated = "PreRated"
- STATIC_VALUE_PREFIX = "^"
- CSV = "csv"
- FWV = "fwv"
- MetaPartialCSV = "*partial_csv"
- DRYRUN = "dry_run"
- META_COMBIMED = "*combimed"
- MetaMongo = "*mongo"
- MetaRedis = "*redis"
- MetaPostgres = "*postgres"
- MetaInternal = "*internal"
- MetaLocalHost = "*localhost"
- ZERO_RATING_SUBJECT_PREFIX = "*zero"
- OK = "OK"
- MetaFileXML = "*file_xml"
- CDRE = "cdre"
- MASK_CHAR = "*"
- CONCATENATED_KEY_SEP = ":"
- UNIT_TEST = "UNIT_TEST"
- HDR_VAL_SEP = "/"
- MONETARY = "*monetary"
- SMS = "*sms"
- MMS = "*mms"
- GENERIC = "*generic"
- DATA = "*data"
- VOICE = "*voice"
- MAX_COST_FREE = "*free"
- MAX_COST_DISCONNECT = "*disconnect"
- SECONDS = "seconds"
- META_OUT = "*out"
- META_ANY = "*any"
- ASR = "ASR"
- ACD = "ACD"
- TASKS_KEY = "tasks"
- ACTION_PLAN_PREFIX = "apl_"
- AccountActionPlansPrefix = "aap_"
- ACTION_TRIGGER_PREFIX = "atr_"
- RATING_PLAN_PREFIX = "rpl_"
- RATING_PROFILE_PREFIX = "rpf_"
- ACTION_PREFIX = "act_"
- SHARED_GROUP_PREFIX = "shg_"
- ACCOUNT_PREFIX = "acc_"
- DESTINATION_PREFIX = "dst_"
- REVERSE_DESTINATION_PREFIX = "rds_"
- DERIVEDCHARGERS_PREFIX = "dcs_"
- USERS_PREFIX = "usr_"
- ResourcesPrefix = "res_"
- ResourceProfilesPrefix = "rsp_"
- ThresholdPrefix = "thd_"
- TimingsPrefix = "tmg_"
- FilterPrefix = "ftr_"
- CDR_STATS_PREFIX = "cst_"
- VERSION_PREFIX = "ver_"
- StatQueueProfilePrefix = "sqp_"
- SupplierProfilePrefix = "spp_"
- AttributeProfilePrefix = "alp_"
- ChargerProfilePrefix = "cpp_"
- DispatcherProfilePrefix = "dpp_"
- DispatcherHostPrefix = "dph_"
- ThresholdProfilePrefix = "thp_"
- StatQueuePrefix = "stq_"
- LoadIDPrefix = "lid_"
- LOADINST_KEY = "load_history"
- CREATE_CDRS_TABLES_SQL = "create_cdrs_tables.sql"
- CREATE_TARIFFPLAN_TABLES_SQL = "create_tariffplan_tables.sql"
- TEST_SQL = "TEST_SQL"
- META_CONSTANT = "*constant"
- META_FILLER = "*filler"
- META_HANDLER = "*handler"
- MetaHTTPPost = "*http_post"
- MetaHTTPjson = "*http_json"
- MetaHTTPjsonCDR = "*http_json_cdr"
- MetaHTTPjsonMap = "*http_json_map"
- MetaAMQPjsonCDR = "*amqp_json_cdr"
- MetaAMQPjsonMap = "*amqp_json_map"
- MetaAMQPV1jsonMap = "*amqpv1_json_map"
- MetaSQSjsonMap = "*sqs_json_map"
- MetaKafkajsonMap = "*kafka_json_map"
- MetaSQL = "*sql"
- MetaMySQL = "*mysql"
- MetaS3jsonMap = "*s3_json_map"
- CONFIG_PATH = "/etc/cgrates/"
- DISCONNECT_CAUSE = "DisconnectCause"
- MetaFlatstore = "*flatstore"
- MetaRating = "*rating"
- NOT_AVAILABLE = "N/A"
- CALL = "call"
- EXTRA_FIELDS = "ExtraFields"
- META_SURETAX = "*sure_tax"
- MetaDynamic = "*dynamic"
- COUNTER_EVENT = "*event"
- COUNTER_BALANCE = "*balance"
- EVENT_NAME = "EventName"
- // action trigger threshold types
- TRIGGER_MIN_EVENT_COUNTER = "*min_event_counter"
- TRIGGER_MAX_EVENT_COUNTER = "*max_event_counter"
- TRIGGER_MAX_BALANCE_COUNTER = "*max_balance_counter"
- TRIGGER_MIN_BALANCE = "*min_balance"
- TRIGGER_MAX_BALANCE = "*max_balance"
- TRIGGER_BALANCE_EXPIRED = "*balance_expired"
- HIERARCHY_SEP = ">"
- META_COMPOSED = "*composed"
- META_USAGE_DIFFERENCE = "*usage_difference"
- MetaSIPCID = "*sipcid"
- MetaDifference = "*difference"
- MetaVariable = "*variable"
- MetaCCUsage = "*cc_usage"
- MetaValueExponent = "*value_exponent"
- NegativePrefix = "!"
- MatchStartPrefix = "^"
- MatchGreaterThanOrEqual = ">="
- MatchLessThanOrEqual = "<="
- MatchGreaterThan = ">"
- MatchLessThan = "<"
- MatchEndPrefix = "$"
- MetaRaw = "*raw"
- CreatedAt = "CreatedAt"
- UpdatedAt = "UpdatedAt"
- HandlerArgSep = "|"
- NodeID = "NodeID"
- ActiveGoroutines = "ActiveGoroutines"
- MemoryUsage = "MemoryUsage"
- RunningSince = "RunningSince"
- GoVersion = "GoVersion"
- SessionTTL = "SessionTTL"
- SessionTTLMaxDelay = "SessionTTLMaxDelay"
- SessionTTLLastUsed = "SessionTTLLastUsed"
- SessionTTLUsage = "SessionTTLUsage"
- SessionTTLLastUsage = "SessionTTLLastUsage"
- HandlerSubstractUsage = "*substract_usage"
- XML = "xml"
- MetaGOB = "*gob"
- MetaJSON = "*json"
- MetaMSGPACK = "*msgpack"
- MetaDateTime = "*datetime"
- MetaMaskedDestination = "*masked_destination"
- MetaUnixTimestamp = "*unix_timestamp"
- MetaPostCDR = "*post_cdr"
- MetaDumpToFile = "*dump_to_file"
- NonTransactional = ""
- DataDB = "data_db"
- StorDB = "stor_db"
- NotFoundCaps = "NOT_FOUND"
- ServerErrorCaps = "SERVER_ERROR"
- MandatoryIEMissingCaps = "MANDATORY_IE_MISSING"
- UnsupportedCachePrefix = "unsupported cache prefix"
- CDRSCtx = "cdrs"
- MandatoryInfoMissing = "mandatory information missing"
- UnsupportedServiceIDCaps = "UNSUPPORTED_SERVICE_ID"
- ServiceManager = "service_manager"
- ServiceAlreadyRunning = "service already running"
- RunningCaps = "RUNNING"
- StoppedCaps = "STOPPED"
- SchedulerNotRunningCaps = "SCHEDULLER_NOT_RUNNING"
- MetaScheduler = "*scheduler"
- MetaSessionsCosts = "*sessions_costs"
- MetaRALs = "*rals"
- MetaRerate = "*rerate"
- MetaRefund = "*refund"
- MetaStats = "*stats"
- MetaResponder = "*responder"
- MetaCore = "*core"
- MetaServiceManager = "*servicemanager"
- MetaChargers = "*chargers"
- MetaConfig = "*config"
- MetaDispatchers = "*dispatchers"
- MetaDispatcherHosts = "*dispatcher_hosts"
- MetaFilters = "*filters"
- MetaCDRs = "*cdrs"
- MetaCaches = "*caches"
- MetaGuardian = "*guardians"
- MetaContinue = "*continue"
- Migrator = "migrator"
- UnsupportedMigrationTask = "unsupported migration task"
- NoStorDBConnection = "not connected to StorDB"
- UndefinedVersion = "undefined version"
- TxtSuffix = ".txt"
- JSNSuffix = ".json"
- GOBSuffix = ".gob"
- FormSuffix = ".form"
- XMLSuffix = ".xml"
- CSVSuffix = ".csv"
- FWVSuffix = ".fwv"
- CONTENT_JSON = "json"
- CONTENT_FORM = "form"
- CONTENT_TEXT = "text"
- FileLockPrefix = "file_"
- ActionsPoster = "act"
- CDRPoster = "cdr"
- MetaFileCSV = "*file_csv"
- MetaFileFWV = "*file_fwv"
- MetaFScsv = "*freeswitch_csv"
- Accounts = "Accounts"
- AccountService = "AccountS"
- Actions = "Actions"
- ActionPlans = "ActionPlans"
- ActionTriggers = "ActionTriggers"
- SharedGroups = "SharedGroups"
- TimingIDs = "TimingIDs"
- Timings = "Timings"
- Rates = "Rates"
- DestinationRates = "DestinationRates"
- RatingPlans = "RatingPlans"
- RatingProfiles = "RatingProfiles"
- AccountActions = "AccountActions"
- Resources = "Resources"
- Stats = "Stats"
- Filters = "Filters"
- DispatcherProfiles = "DispatcherProfiles"
- DispatcherHosts = "DispatcherHosts"
- MetaEveryMinute = "*every_minute"
- MetaHourly = "*hourly"
- ID = "ID"
- Thresholds = "Thresholds"
- Suppliers = "Suppliers"
- Attributes = "Attributes"
- Chargers = "Chargers"
- Dispatchers = "Dispatchers"
- StatS = "Stats"
- LoadIDsVrs = "LoadIDs"
- RALService = "RALs"
- CostSource = "CostSource"
- ExtraInfo = "ExtraInfo"
- Meta = "*"
- MetaSysLog = "*syslog"
- MetaStdLog = "*stdout"
- EventType = "EventType"
- EventSource = "EventSource"
- AccountID = "AccountID"
- ResourceID = "ResourceID"
- TotalUsage = "TotalUsage"
- StatID = "StatID"
- BalanceType = "BalanceType"
- BalanceID = "BalanceID"
- BalanceDestinationIds = "BalanceDestinationIds"
- BalanceWeight = "BalanceWeight"
- BalanceExpirationDate = "BalanceExpirationDate"
- BalanceTimingTags = "BalanceTimingTags"
- BalanceRatingSubject = "BalanceRatingSubject"
- BalanceCategories = "BalanceCategories"
- BalanceSharedGroups = "BalanceSharedGroups"
- BalanceBlocker = "BalanceBlocker"
- BalanceDisabled = "BalanceDisabled"
- Units = "Units"
- AccountUpdate = "AccountUpdate"
- BalanceUpdate = "BalanceUpdate"
- StatUpdate = "StatUpdate"
- ResourceUpdate = "ResourceUpdate"
- CDR = "CDR"
- CDRs = "CDRs"
- ExpiryTime = "ExpiryTime"
- AllowNegative = "AllowNegative"
- Disabled = "Disabled"
- Action = "Action"
- MetaNow = "*now"
- SessionSCosts = "SessionSCosts"
- Timing = "Timing"
- RQF = "RQF"
- Resource = "Resource"
- User = "User"
- Subscribers = "Subscribers"
- DerivedChargersV = "DerivedChargers"
- Destinations = "Destinations"
- ReverseDestinations = "ReverseDestinations"
- RatingPlan = "RatingPlan"
- RatingProfile = "RatingProfile"
- MetaRatingPlans = "*rating_plans"
- MetaRatingProfiles = "*rating_profiles"
- MetaUsers = "*users"
- MetaSubscribers = "*subscribers"
- MetaDerivedChargersV = "*derivedchargers"
- MetaStorDB = "*stordb"
- MetaDataDB = "*datadb"
- MetaWeight = "*weight"
- MetaLC = "*lc"
- MetaHC = "*hc"
- MetaQOS = "*qos"
- MetaReas = "*reas"
- MetaReds = "*reds"
- Weight = "Weight"
- Cost = "Cost"
- DestinationIDs = "DestinationIDs"
- RatingSubject = "RatingSubject"
- Categories = "Categories"
- Blocker = "Blocker"
- RatingPlanID = "RatingPlanID"
- StartTime = "StartTime"
- AccountSummary = "AccountSummary"
- RatingFilters = "RatingFilters"
- RatingFilter = "RatingFilter"
- Accounting = "Accounting"
- Rating = "Rating"
- Charges = "Charges"
- CompressFactor = "CompressFactor"
- Increments = "Increments"
- Balance = "Balance"
- BalanceSummaries = "BalanceSummaries"
- Type = "Type"
- YearsFieldName = "Years"
- MonthsFieldName = "Months"
- MonthDaysFieldName = "MonthDays"
- WeekDaysFieldName = "WeekDays"
- GroupIntervalStart = "GroupIntervalStart"
- RateIncrement = "RateIncrement"
- RateUnit = "RateUnit"
- BalanceUUID = "BalanceUUID"
- RatingID = "RatingID"
- ExtraChargeID = "ExtraChargeID"
- ConnectFee = "ConnectFee"
- RoundingMethod = "RoundingMethod"
- RoundingDecimals = "RoundingDecimals"
- MaxCostStrategy = "MaxCostStrategy"
- TimingID = "TimingID"
- RatesID = "RatesID"
- RatingFiltersID = "RatingFiltersID"
- AccountingID = "AccountingID"
- MetaSessionS = "*sessions"
- MetaDefault = "*default"
- Error = "Error"
- MetaCgreq = "*cgreq"
- MetaCgrep = "*cgrep"
- MetaCGRAReq = "*cgrareq"
- CGR_ACD = "cgr_acd"
- FilterIDs = "FilterIDs"
- FieldName = "FieldName"
- Path = "Path"
- MetaRound = "*round"
- Pong = "Pong"
- MetaEventCost = "*event_cost"
- MetaSuppliersMaxCost = "*suppliers_maxcost"
- MetaMaxCost = "*maxcost"
- MetaSuppliersEventCost = "*suppliers_event_cost"
- MetaSuppliersIgnoreErrors = "*suppliers_ignore_errors"
- Freeswitch = "freeswitch"
- Kamailio = "kamailio"
- Opensips = "opensips"
- Asterisk = "asterisk"
- SchedulerS = "SchedulerS"
- MetaMultiply = "*multiply"
- MetaDivide = "*divide"
- MetaUrl = "*url"
- MetaXml = "*xml"
- ApiKey = "apikey"
- MetaReq = "*req"
- MetaVars = "*vars"
- MetaRep = "*rep"
- MetaExp = "*exp"
- MetaHdr = "*hdr"
- MetaTrl = "*trl"
- MetaTmp = "*tmp"
- CGROriginHost = "cgr_originhost"
- MetaInitiate = "*initiate"
- MetaFD = "*fd"
- MetaUpdate = "*update"
- MetaTerminate = "*terminate"
- MetaEvent = "*event"
- MetaMessage = "*message"
- MetaDryRun = "*dryrun"
- Event = "Event"
- EmptyString = ""
- DynamicDataPrefix = "~"
- AttrValueSep = "="
- ANDSep = "&"
- PipeSep = "|"
- MetaApp = "*app"
- MetaAppID = "*appid"
- MetaCmd = "*cmd"
- MetaEnv = "*env:" // use in config for describing enviormant variables
- MetaTemplate = "*template"
- MetaCCA = "*cca"
- MetaErr = "*err"
- OriginRealm = "OriginRealm"
- ProductName = "ProductName"
- IdxStart = "["
- IdxEnd = "]"
- MetaLog = "*log"
- MetaRemoteHost = "*remote_host"
- RemoteHost = "RemoteHost"
- Local = "local"
- TCP = "tcp"
- CGRDebitInterval = "CGRDebitInterval"
- Version = "Version"
- MetaTenant = "*tenant"
- ResourceUsage = "ResourceUsage"
- MetaDuration = "*duration"
- MetaLibPhoneNumber = "*libphonenumber"
- MetaIP2Hex = "*ip2hex"
- MetaString2Hex = "*string2hex"
- MetaReload = "*reload"
- MetaLoad = "*load"
- MetaRemove = "*remove"
- MetaRemoveAll = "*removeall"
- MetaStore = "*store"
- MetaClear = "*clear"
- MetaExport = "*export"
- LoadIDs = "load_ids"
- DNSAgent = "DNSAgent"
- TLSNoCaps = "tls"
- MetaRouteID = "*route_id"
- MetaApiKey = "*api_key"
- UsageID = "UsageID"
- Rcode = "Rcode"
- Replacement = "Replacement"
- Regexp = "Regexp"
- Order = "Order"
- Preference = "Preference"
- Flags = "Flags"
- Service = "Service"
- MetaSuppliersLimit = "*suppliers_limit"
- MetaSuppliersOffset = "*suppliers_offset"
- ApierV = "ApierV"
- MetaApier = "*apier"
- MetaAnalyzer = "*analyzer"
- CGREventString = "CGREvent"
- MetaTextPlain = "*text_plain"
- MetaIgnoreErrors = "*ignore_errors"
- MetaRelease = "*release"
- MetaAllocate = "*allocate"
- MetaAuthorize = "*authorize"
- MetaInit = "*init"
- MetaRatingPlanCost = "*rating_plan_cost"
- RatingPlanIDs = "RatingPlanIDs"
- ERs = "ERs"
- Ratio = "Ratio"
- Load = "Load"
- Slash = "/"
- UUID = "UUID"
- ActionsID = "ActionsID"
- MetaAct = "*act"
- DestinationPrefix = "DestinationPrefix"
- DestinationID = "DestinationID"
- ExportTemplate = "ExportTemplate"
- ExportFormat = "ExportFormat"
- Synchronous = "Synchronous"
- Attempts = "Attempts"
- FieldSeparator = "FieldSeparator"
- ExportPath = "ExportPath"
- ExportID = "ExportID"
- ExportFileName = "ExportFileName"
- GroupID = "GroupID"
- ThresholdType = "ThresholdType"
- ThresholdValue = "ThresholdValue"
- Recurrent = "Recurrent"
- Executed = "Executed"
- MinSleep = "MinSleep"
- ActivationDate = "ActivationDate"
- ExpirationDate = "ExpirationDate"
- MinQueuedItems = "MinQueuedItems"
- OrderIDStart = "OrderIDStart"
- OrderIDEnd = "OrderIDEnd"
- MinCost = "MinCost"
- MaxCost = "MaxCost"
- MetaLoaders = "*loaders"
- TmpSuffix = ".tmp"
- MetaDiamreq = "*diamreq"
- MetaGroup = "*group"
- InternalRPCSet = "InternalRPCSet"
- MetaFileName = "*fileName"
- MetaBusy = "*busy"
- MetaQueue = "*queue"
- MetaRounding = "*rounding"
-)
-
-// Migrator Action
-const (
- Move = "move"
- Migrate = "migrate"
-)
-
-// Meta Items
-const (
- MetaAccounts = "*accounts"
- MetaAccountActionPlans = "*account_action_plans"
- MetaReverseDestinations = "*reverse_destinations"
- MetaActionPlans = "*action_plans"
- MetaActionTriggers = "*action_triggers"
- MetaActions = "*actions"
- MetaResourceProfile = "*resource_profiles"
- MetaStatQueueProfiles = "*statqueue_profiles"
- MetaStatQueues = "*statqueues"
- MetaThresholdProfiles = "*threshold_profiles"
- MetaSupplierProfiles = "*supplier_profiles"
- MetaAttributeProfiles = "*attribute_profiles"
- MetaFilterIndexes = "*filter_indexes"
- MetaDispatcherProfiles = "*dispatcher_profiles"
- MetaChargerProfiles = "*charger_profiles"
- MetaSharedGroups = "*shared_groups"
- MetaThresholds = "*thresholds"
- MetaSuppliers = "*suppliers"
- MetaAttributes = "*attributes"
- MetaLoadIDs = "*load_ids"
-)
-
-// MetaMetrics
-const (
- MetaASR = "*asr"
- MetaACD = "*acd"
- MetaTCD = "*tcd"
- MetaACC = "*acc"
- MetaTCC = "*tcc"
- MetaPDD = "*pdd"
- MetaDDC = "*ddc"
- MetaSum = "*sum"
- MetaAverage = "*average"
- MetaDistinct = "*distinct"
-)
-
-// Services
-const (
- SessionS = "SessionS"
- AttributeS = "AttributeS"
- SupplierS = "SupplierS"
- ResourceS = "ResourceS"
- StatService = "StatS"
- FilterS = "FilterS"
- ThresholdS = "ThresholdS"
- DispatcherS = "DispatcherS"
- LoaderS = "LoaderS"
- ChargerS = "ChargerS"
- CacheS = "CacheS"
- AnalyzerS = "AnalyzerS"
- CDRServer = "CDRServer"
- ResponderS = "ResponderS"
- GuardianS = "GuardianS"
- ApierS = "ApierS"
-)
-
-// Lower service names
-const (
- SessionsLow = "sessions"
- AttributesLow = "attributes"
- ChargerSLow = "chargers"
- SuppliersLow = "suppliers"
- ResourcesLow = "resources"
- StatServiceLow = "stats"
- ThresholdsLow = "thresholds"
- DispatcherSLow = "dispatchers"
- AnalyzerSLow = "analyzers"
- SchedulerSLow = "schedulers"
- LoaderSLow = "loaders"
- RALsLow = "rals"
- ReplicatorLow = "replicator"
- ApierSLow = "apiers"
-)
-
-// Actions
-const (
- LOG = "*log"
- RESET_TRIGGERS = "*reset_triggers"
- SET_RECURRENT = "*set_recurrent"
- UNSET_RECURRENT = "*unset_recurrent"
- ALLOW_NEGATIVE = "*allow_negative"
- DENY_NEGATIVE = "*deny_negative"
- RESET_ACCOUNT = "*reset_account"
- REMOVE_ACCOUNT = "*remove_account"
- SET_BALANCE = "*set_balance"
- REMOVE_BALANCE = "*remove_balance"
- TOPUP_RESET = "*topup_reset"
- TOPUP = "*topup"
- DEBIT_RESET = "*debit_reset"
- DEBIT = "*debit"
- RESET_COUNTERS = "*reset_counters"
- ENABLE_ACCOUNT = "*enable_account"
- DISABLE_ACCOUNT = "*disable_account"
- HttpPost = "*http_post"
- HttpPostAsync = "*http_post_async"
- MAIL_ASYNC = "*mail_async"
- UNLIMITED = "*unlimited"
- CDRLOG = "*cdrlog"
- SET_DDESTINATIONS = "*set_ddestinations"
- TRANSFER_MONETARY_DEFAULT = "*transfer_monetary_default"
- CGR_RPC = "*cgr_rpc"
- TopUpZeroNegative = "*topup_zero_negative"
- SetExpiry = "*set_expiry"
- MetaPublishAccount = "*publish_account"
- MetaPublishBalance = "*publish_balance"
- MetaRemoveSessionCosts = "*remove_session_costs"
- MetaRemoveExpired = "*remove_expired"
- MetaPostEvent = "*post_event"
- MetaCDRAccount = "*cdr_account"
-)
-
-// Migrator Metas
-const (
- MetaSetVersions = "*set_versions"
- MetaEnsureIndexes = "*ensure_indexes"
- MetaTpRatingPlans = "*tp_rating_plans"
- MetaTpFilters = "*tp_filters"
- MetaTpDestinationRates = "*tp_destination_rates"
- MetaTpActionTriggers = "*tp_action_triggers"
- MetaTpAccountActions = "*tp_account_actions"
- MetaTpActionPlans = "*tp_action_plans"
- MetaTpActions = "*tp_actions"
- MetaTpThresholds = "*tp_thresholds"
- MetaTpSuppliers = "*tp_suppliers"
- MetaTpStats = "*tp_stats"
- MetaTpSharedGroups = "*tp_shared_groups"
- MetaTpRatingProfiles = "*tp_rating_profiles"
- MetaTpResources = "*tp_resources"
- MetaTpRates = "*tp_rates"
- MetaTpTimings = "*tp_timings"
- MetaTpDestinations = "*tp_destinations"
- MetaTpChargers = "*tp_chargers"
- MetaTpDispatchers = "*tp_dispatchers"
- MetaDurationSeconds = "*duration_seconds"
- MetaDurationNanoseconds = "*duration_nanoseconds"
- CapAttributes = "Attributes"
- CapResourceAllocation = "ResourceAllocation"
- CapMaxUsage = "MaxUsage"
- CapSuppliers = "Suppliers"
- CapThresholds = "Thresholds"
- CapStatQueues = "StatQueues"
-)
-
-const (
- TpRatingPlans = "TpRatingPlans"
- TpFilters = "TpFilters"
- TpDestinationRates = "TpDestinationRates"
- TpActionTriggers = "TpActionTriggers"
- TpAccountActionsV = "TpAccountActions"
- TpActionPlans = "TpActionPlans"
- TpActions = "TpActions"
- TpThresholds = "TpThresholds"
- TpSuppliers = "TpSuppliers"
- TpStats = "TpStats"
- TpSharedGroups = "TpSharedGroups"
- TpRatingProfiles = "TpRatingProfiles"
- TpResources = "TpResources"
- TpRates = "TpRates"
- TpTiming = "TpTiming"
- TpResource = "TpResource"
- TpDestinations = "TpDestinations"
- TpRatingPlan = "TpRatingPlan"
- TpRatingProfile = "TpRatingProfile"
- TpChargers = "TpChargers"
- TpDispatchers = "TpDispatchers"
-)
-
-// Dispatcher Const
-const (
- MetaFirst = "*first"
- MetaRandom = "*random"
- MetaBroadcast = "*broadcast"
- MetaRoundRobin = "*round_robin"
- MetaRatio = "*ratio"
- ThresholdSv1 = "ThresholdSv1"
- StatSv1 = "StatSv1"
- ResourceSv1 = "ResourceSv1"
- SupplierSv1 = "SupplierSv1"
- AttributeSv1 = "AttributeSv1"
- SessionSv1 = "SessionSv1"
- ChargerSv1 = "ChargerSv1"
- MetaAuth = "*auth"
- APIKey = "APIKey"
- RouteID = "RouteID"
- APIMethods = "APIMethods"
- NestingSep = "."
- ArgDispatcherField = "ArgDispatcher"
-)
-
-// Filter types
-const (
- MetaNot = "*not"
- MetaString = "*string"
- MetaPrefix = "*prefix"
- MetaSuffix = "*suffix"
- MetaEmpty = "*empty"
- MetaExists = "*exists"
- MetaTimings = "*timings"
- MetaRSR = "*rsr"
- MetaStatS = "*stats"
- MetaDestinations = "*destinations"
- MetaLessThan = "*lt"
- MetaLessOrEqual = "*lte"
- MetaGreaterThan = "*gt"
- MetaGreaterOrEqual = "*gte"
- MetaResources = "*resources"
- MetaEqual = "*eq"
-
- MetaNotString = "*notstring"
- MetaNotPrefix = "*notprefix"
- MetaNotSuffix = "*notsuffix"
- MetaNotEmpty = "*notempty"
- MetaNotExists = "*notexists"
- MetaNotTimings = "*nottimings"
- MetaNotRSR = "*notrsr"
- MetaNotStatS = "*notstats"
- MetaNotDestinations = "*notdestinations"
- MetaNotResources = "*notresources"
- MetaNotEqual = "*noteq"
-
- MetaEC = "*ec"
-)
-
-// ReplicatorSv1 APIs
-const (
- ReplicatorSv1 = "ReplicatorSv1"
- ReplicatorSv1Ping = "ReplicatorSv1.Ping"
- ReplicatorSv1GetAccount = "ReplicatorSv1.GetAccount"
- ReplicatorSv1GetDestination = "ReplicatorSv1.GetDestination"
- ReplicatorSv1GetReverseDestination = "ReplicatorSv1.GetReverseDestination"
- ReplicatorSv1GetStatQueue = "ReplicatorSv1.GetStatQueue"
- ReplicatorSv1GetFilter = "ReplicatorSv1.GetFilter"
- ReplicatorSv1GetThreshold = "ReplicatorSv1.GetThreshold"
- ReplicatorSv1GetThresholdProfile = "ReplicatorSv1.GetThresholdProfile"
- ReplicatorSv1GetStatQueueProfile = "ReplicatorSv1.GetStatQueueProfile"
- ReplicatorSv1GetTiming = "ReplicatorSv1.GetTiming"
- ReplicatorSv1GetResource = "ReplicatorSv1.GetResource"
- ReplicatorSv1GetResourceProfile = "ReplicatorSv1.GetResourceProfile"
- ReplicatorSv1GetActionTriggers = "ReplicatorSv1.GetActionTriggers"
- ReplicatorSv1GetShareGroup = "ReplicatorSv1.GetShareGroup"
- ReplicatorSv1GetActions = "ReplicatorSv1.GetActions"
- ReplicatorSv1GetActionPlan = "ReplicatorSv1.GetActionPlan"
- ReplicatorSv1GetAllActionPlans = "ReplicatorSv1.GetAllActionPlans"
- ReplicatorSv1GetAccountActionPlans = "ReplicatorSv1.GetAccountActionPlans"
- ReplicatorSv1GetRatingPlan = "ReplicatorSv1.GetRatingPlan"
- ReplicatorSv1GetRatingProfile = "ReplicatorSv1.GetRatingProfile"
- ReplicatorSv1GetSupplierProfile = "ReplicatorSv1.GetSupplierProfile"
- ReplicatorSv1GetAttributeProfile = "ReplicatorSv1.GetAttributeProfile"
- ReplicatorSv1GetChargerProfile = "ReplicatorSv1.GetChargerProfile"
- ReplicatorSv1GetDispatcherProfile = "ReplicatorSv1.GetDispatcherProfile"
- ReplicatorSv1GetDispatcherHost = "ReplicatorSv1.GetDispatcheHost"
- ReplicatorSv1GetItemLoadIDs = "ReplicatorSv1.GetItemLoadIDs"
- ReplicatorSv1GetFilterIndexes = "ReplicatorSv1.GetFilterIndexes"
- ReplicatorSv1MatchFilterIndex = "ReplicatorSv1.MatchFilterIndex"
- ReplicatorSv1SetThresholdProfile = "ReplicatorSv1.SetThresholdProfile"
- ReplicatorSv1SetThreshold = "ReplicatorSv1.SetThreshold"
- ReplicatorSv1SetFilterIndexes = "ReplicatorSv1.SetFilterIndexes"
- ReplicatorSv1Account = "ReplicatorSv1.SetAccount"
- ReplicatorSv1SetDestination = "ReplicatorSv1.SetDestination"
- ReplicatorSv1SetReverseDestination = "ReplicatorSv1.SetReverseDestination"
- ReplicatorSv1SetStatQueue = "ReplicatorSv1.SetStatQueue"
- ReplicatorSv1SetFilter = "ReplicatorSv1.SetFilter"
- ReplicatorSv1SetStatQueueProfile = "ReplicatorSv1.SetStatQueueProfile"
- ReplicatorSv1SetTiming = "ReplicatorSv1.SetTiming"
- ReplicatorSv1SetResource = "ReplicatorSv1.SetResource"
- ReplicatorSv1SetResourceProfile = "ReplicatorSv1.SetResourceProfile"
- ReplicatorSv1SetActionTriggers = "ReplicatorSv1.SetActionTriggers"
- ReplicatorSv1SetSharedGroup = "ReplicatorSv1.SetSharedGroup"
- ReplicatorSv1SetActions = "ReplicatorSv1.SetActions"
- ReplicatorSv1SetActionPlan = "ReplicatorSv1.SetActionPlan"
- ReplicatorSv1SetAccountActionPlans = "ReplicatorSv1.SetAccountActionPlans"
- ReplicatorSv1SetRatingPlan = "ReplicatorSv1.SetRatingPlan"
- ReplicatorSv1SetRatingProfile = "ReplicatorSv1.SetRatingProfile"
- ReplicatorSv1SetSupplierProfile = "ReplicatorSv1.SetSupplierProfile"
- ReplicatorSv1SetAttributeProfile = "ReplicatorSv1.SetAttributeProfile"
- ReplicatorSv1SetChargerProfile = "ReplicatorSv1.SetChargerProfile"
- ReplicatorSv1SetDispatcherProfile = "ReplicatorSv1.SetDispatcherProfile"
- ReplicatorSv1SetDispatcherHost = "ReplicatorSv1.SetDispatcherHost"
- ReplicatorSv1SetLoadIDs = "ReplicatorSv1.SetLoadIDs"
- ReplicatorSv1RemoveThreshold = "ReplicatorSv1.RemoveThreshold"
- ReplicatorSv1RemoveDestination = "ReplicatorSv1.RemoveDestination"
- ReplicatorSv1RemoveAccount = "ReplicatorSv1.RemoveAccount"
- ReplicatorSv1RemoveStatQueue = "ReplicatorSv1.RemoveStatQueue"
- ReplicatorSv1RemoveFilter = "ReplicatorSv1.RemoveFilter"
- ReplicatorSv1RemoveThresholdProfile = "ReplicatorSv1.RemoveThresholdProfile"
- ReplicatorSv1RemoveStatQueueProfile = "ReplicatorSv1.RemoveStatQueueProfile"
- ReplicatorSv1RemoveTiming = "ReplicatorSv1.RemoveTiming"
- ReplicatorSv1RemoveResource = "ReplicatorSv1.RemoveResource"
- ReplicatorSv1RemoveResourceProfile = "ReplicatorSv1.RemoveResourceProfile"
- ReplicatorSv1RemoveActionTriggers = "ReplicatorSv1.RemoveActionTriggers"
- ReplicatorSv1RemoveSharedGroup = "ReplicatorSv1.RemoveSharedGroup"
- ReplicatorSv1RemoveActions = "ReplicatorSv1.RemoveActions"
- ReplicatorSv1RemoveActionPlan = "ReplicatorSv1.RemoveActionPlan"
- ReplicatorSv1RemAccountActionPlans = "ReplicatorSv1.RemAccountActionPlans"
- ReplicatorSv1RemoveRatingPlan = "ReplicatorSv1.RemoveRatingPlan"
- ReplicatorSv1RemoveRatingProfile = "ReplicatorSv1.RemoveRatingProfile"
- ReplicatorSv1RemoveSupplierProfile = "ReplicatorSv1.RemoveSupplierProfile"
- ReplicatorSv1RemoveAttributeProfile = "ReplicatorSv1.RemoveAttributeProfile"
- ReplicatorSv1RemoveChargerProfile = "ReplicatorSv1.RemoveChargerProfile"
- ReplicatorSv1RemoveDispatcherProfile = "ReplicatorSv1.RemoveDispatcherProfile"
- ReplicatorSv1RemoveDispatcherHost = "ReplicatorSv1.RemoveDispatcherHost"
-)
-
-// APIerSv1 APIs
-const (
- ApierV1 = "ApierV1"
- ApierV2 = "ApierV2"
- APIerSv1 = "APIerSv1"
- APIerSv1ComputeFilterIndexes = "APIerSv1.ComputeFilterIndexes"
- APIerSv1ComputeFilterIndexIDs = "APIerSv1.ComputeFilterIndexIDs"
- APIerSv1Ping = "APIerSv1.Ping"
- APIerSv1SetDispatcherProfile = "APIerSv1.SetDispatcherProfile"
- APIerSv1GetDispatcherProfile = "APIerSv1.GetDispatcherProfile"
- APIerSv1GetDispatcherProfileIDs = "APIerSv1.GetDispatcherProfileIDs"
- APIerSv1RemoveDispatcherProfile = "APIerSv1.RemoveDispatcherProfile"
- APIerSv1SetDispatcherHost = "APIerSv1.SetDispatcherHost"
- APIerSv1GetDispatcherHost = "APIerSv1.GetDispatcherHost"
- APIerSv1GetDispatcherHostIDs = "APIerSv1.GetDispatcherHostIDs"
- APIerSv1RemoveDispatcherHost = "APIerSv1.RemoveDispatcherHost"
- APIerSv1GetEventCost = "APIerSv1.GetEventCost"
- APIerSv1LoadTariffPlanFromFolder = "APIerSv1.LoadTariffPlanFromFolder"
- APIerSv1GetCost = "APIerSv1.GetCost"
- APIerSv1SetBalance = "APIerSv1.SetBalance"
- APIerSv1GetFilter = "APIerSv1.GetFilter"
- APIerSv1GetFilterIndexes = "APIerSv1.GetFilterIndexes"
- APIerSv1RemoveFilterIndexes = "APIerSv1.RemoveFilterIndexes"
- APIerSv1RemoveFilter = "APIerSv1.RemoveFilter"
- APIerSv1SetFilter = "APIerSv1.SetFilter"
- APIerSv1GetFilterIDs = "APIerSv1.GetFilterIDs"
- APIerSv1GetAccountActionPlansIndexHealth = "APIerSv1.GetAccountActionPlansIndexHealth"
- APIerSv1GetReverseDestinationsIndexHealth = "APIerSv1.GetReverseDestinationsIndexHealth"
- APIerSv1GetThresholdsIndexesHealth = "APIerSv1.GetThresholdsIndexesHealth"
- APIerSv1GetResourcesIndexesHealth = "APIerSv1.GetResourcesIndexesHealth"
- APIerSv1GetStatsIndexesHealth = "APIerSv1.GetStatsIndexesHealth"
- APIerSv1GetSuppliersIndexesHealth = "APIerSv1.GetSuppliersIndexesHealth"
- APIerSv1GetChargersIndexesHealth = "APIerSv1.GetChargersIndexesHealth"
- APIerSv1GetAttributesIndexesHealth = "APIerSv1.GetAttributesIndexesHealth"
- APIerSv1GetDispatchersIndexesHealth = "APIerSv1.GetDispatchersIndexesHealth"
- APIerSv1GetRatingProfile = "APIerSv1.GetRatingProfile"
- APIerSv1RemoveRatingProfile = "APIerSv1.RemoveRatingProfile"
- APIerSv1SetRatingProfile = "APIerSv1.SetRatingProfile"
- APIerSv1GetRatingProfileIDs = "APIerSv1.GetRatingProfileIDs"
- APIerSv1SetDataDBVersions = "APIerSv1.SetDataDBVersions"
- APIerSv1SetStorDBVersions = "APIerSv1.SetStorDBVersions"
- APIerSv1GetAccountActionPlan = "APIerSv1.GetAccountActionPlan"
- APIerSv1ComputeActionPlanIndexes = "APIerSv1.ComputeActionPlanIndexes"
- APIerSv1GetActions = "APIerSv1.GetActions"
- APIerSv1GetActionPlan = "APIerSv1.GetActionPlan"
- APIerSv1GetActionPlanIDs = "APIerSv1.GetActionPlanIDs"
- APIerSv1GetRatingPlanIDs = "APIerSv1.GetRatingPlanIDs"
- APIerSv1GetRatingPlan = "APIerSv1.GetRatingPlan"
- APIerSv1RemoveRatingPlan = "APIerSv1.RemoveRatingPlan"
- APIerSv1GetDestination = "APIerSv1.GetDestination"
- APIerSv1GetReverseDestination = "APIerSv1.GetReverseDestination"
- APIerSv1AddBalance = "APIerSv1.AddBalance"
- APIerSv1DebitBalance = "APIerSv1.DebitBalance"
- APIerSv1SetAccount = "APIerSv1.SetAccount"
- APIerSv1GetAccountsCount = "APIerSv1.GetAccountsCount"
- APIerSv1GetDataDBVersions = "APIerSv1.GetDataDBVersions"
- APIerSv1GetStorDBVersions = "APIerSv1.GetStorDBVersions"
- APIerSv1GetCDRs = "APIerSv1.GetCDRs"
- APIerSv1GetTPAccountActions = "APIerSv1.GetTPAccountActions"
- APIerSv1SetTPAccountActions = "APIerSv1.SetTPAccountActions"
- APIerSv1GetTPAccountActionsByLoadId = "APIerSv1.GetTPAccountActionsByLoadId"
- APIerSv1GetTPAccountActionLoadIds = "APIerSv1.GetTPAccountActionLoadIds"
- APIerSv1GetTPAccountActionIds = "APIerSv1.GetTPAccountActionIds"
- APIerSv1RemoveTPAccountActions = "APIerSv1.RemoveTPAccountActions"
- APIerSv1GetTPActionPlan = "APIerSv1.GetTPActionPlan"
- APIerSv1SetTPActionPlan = "APIerSv1.SetTPActionPlan"
- APIerSv1GetTPActionPlanIds = "APIerSv1.GetTPActionPlanIds"
- APIerSv1SetTPActionTriggers = "APIerSv1.SetTPActionTriggers"
- APIerSv1GetTPActionTriggers = "APIerSv1.GetTPActionTriggers"
- APIerSv1RemoveTPActionTriggers = "APIerSv1.RemoveTPActionTriggers"
- APIerSv1GetTPActionTriggerIds = "APIerSv1.GetTPActionTriggerIds"
- APIerSv1GetTPActions = "APIerSv1.GetTPActions"
- APIerSv1RemoveTPActionPlan = "APIerSv1.RemoveTPActionPlan"
- APIerSv1GetTPAttributeProfile = "APIerSv1.GetTPAttributeProfile"
- APIerSv1SetTPAttributeProfile = "APIerSv1.SetTPAttributeProfile"
- APIerSv1GetTPAttributeProfileIds = "APIerSv1.GetTPAttributeProfileIds"
- APIerSv1RemoveTPAttributeProfile = "APIerSv1.RemoveTPAttributeProfile"
- APIerSv1GetTPCharger = "APIerSv1.GetTPCharger"
- APIerSv1SetTPCharger = "APIerSv1.SetTPCharger"
- APIerSv1RemoveTPCharger = "APIerSv1.RemoveTPCharger"
- APIerSv1GetTPChargerIDs = "APIerSv1.GetTPChargerIDs"
- APIerSv1SetTPFilterProfile = "APIerSv1.SetTPFilterProfile"
- APIerSv1GetTPFilterProfile = "APIerSv1.GetTPFilterProfile"
- APIerSv1GetTPFilterProfileIds = "APIerSv1.GetTPFilterProfileIds"
- APIerSv1RemoveTPFilterProfile = "APIerSv1.RemoveTPFilterProfile"
- APIerSv1GetTPDestination = "APIerSv1.GetTPDestination"
- APIerSv1SetTPDestination = "APIerSv1.SetTPDestination"
- APIerSv1GetTPDestinationIDs = "APIerSv1.GetTPDestinationIDs"
- APIerSv1RemoveTPDestination = "APIerSv1.RemoveTPDestination"
- APIerSv1GetTPResource = "APIerSv1.GetTPResource"
- APIerSv1SetTPResource = "APIerSv1.SetTPResource"
- APIerSv1RemoveTPResource = "APIerSv1.RemoveTPResource"
- APIerSv1SetTPRate = "APIerSv1.SetTPRate"
- APIerSv1GetTPRate = "APIerSv1.GetTPRate"
- APIerSv1RemoveTPRate = "APIerSv1.RemoveTPRate"
- APIerSv1GetTPRateIds = "APIerSv1.GetTPRateIds"
- APIerSv1SetTPThreshold = "APIerSv1.SetTPThreshold"
- APIerSv1GetTPThreshold = "APIerSv1.GetTPThreshold"
- APIerSv1GetTPThresholdIDs = "APIerSv1.GetTPThresholdIDs"
- APIerSv1RemoveTPThreshold = "APIerSv1.RemoveTPThreshold"
- APIerSv1SetTPStat = "APIerSv1.SetTPStat"
- APIerSv1GetTPStat = "APIerSv1.GetTPStat"
- APIerSv1RemoveTPStat = "APIerSv1.RemoveTPStat"
- APIerSv1GetTPDestinationRate = "APIerSv1.GetTPDestinationRate"
- APIerSv1SetTPSupplierProfile = "APIerSv1.SetTPSupplierProfile"
- APIerSv1GetTPSupplierProfile = "APIerSv1.GetTPSupplierProfile"
- APIerSv1GetTPSupplierProfileIDs = "APIerSv1.GetTPSupplierProfileIDs"
- APIerSv1RemoveTPSupplierProfile = "APIerSv1.RemoveTPSupplierProfile"
- APIerSv1GetTPDispatcherProfile = "APIerSv1.GetTPDispatcherProfile"
- APIerSv1SetTPDispatcherProfile = "APIerSv1.SetTPDispatcherProfile"
- APIerSv1RemoveTPDispatcherProfile = "APIerSv1.RemoveTPDispatcherProfile"
- APIerSv1GetTPDispatcherProfileIDs = "APIerSv1.GetTPDispatcherProfileIDs"
- APIerSv1GetTPSharedGroups = "APIerSv1.GetTPSharedGroups"
- APIerSv1SetTPSharedGroups = "APIerSv1.SetTPSharedGroups"
- APIerSv1GetTPSharedGroupIds = "APIerSv1.GetTPSharedGroupIds"
- APIerSv1RemoveTPSharedGroups = "APIerSv1.RemoveTPSharedGroups"
- APIerSv1ExportCDRs = "APIerSv1.ExportCDRs"
- APIerSv1GetTPRatingPlan = "APIerSv1.GetTPRatingPlan"
- APIerSv1SetTPRatingPlan = "APIerSv1.SetTPRatingPlan"
- APIerSv1GetTPRatingPlanIds = "APIerSv1.GetTPRatingPlanIds"
- APIerSv1RemoveTPRatingPlan = "APIerSv1.RemoveTPRatingPlan"
- APIerSv1SetTPActions = "APIerSv1.SetTPActions"
- APIerSv1GetTPActionIds = "APIerSv1.GetTPActionIds"
- APIerSv1RemoveTPActions = "APIerSv1.RemoveTPActions"
- APIerSv1SetActionPlan = "APIerSv1.SetActionPlan"
- APIerSv1ExecuteAction = "APIerSv1.ExecuteAction"
- APIerSv1SetTPRatingProfile = "APIerSv1.SetTPRatingProfile"
- APIerSv1GetTPRatingProfile = "APIerSv1.GetTPRatingProfile"
- APIerSv1RemoveTPRatingProfile = "APIerSv1.RemoveTPRatingProfile"
- APIerSv1SetTPDestinationRate = "APIerSv1.SetTPDestinationRate"
- APIerSv1GetTPRatingProfileLoadIds = "APIerSv1.GetTPRatingProfileLoadIds"
- APIerSv1GetTPRatingProfilesByLoadID = "APIerSv1.GetTPRatingProfilesByLoadID"
- APIerSv1GetTPRatingProfileIds = "APIerSv1.GetTPRatingProfileIds"
- APIerSv1GetTPDestinationRateIds = "APIerSv1.GetTPDestinationRateIds"
- APIerSv1RemoveTPDestinationRate = "APIerSv1.RemoveTPDestinationRate"
- APIerSv1ImportTariffPlanFromFolder = "APIerSv1.ImportTariffPlanFromFolder"
- APIerSv1ExportTPToFolder = "APIerSv1.ExportTPToFolder"
- APIerSv1LoadRatingPlan = "APIerSv1.LoadRatingPlan"
- APIerSv1LoadRatingProfile = "APIerSv1.LoadRatingProfile"
- APIerSv1LoadAccountActions = "APIerSv1.LoadAccountActions"
- APIerSv1SetActions = "APIerSv1.SetActions"
- APIerSv1AddTriggeredAction = "APIerSv1.AddTriggeredAction"
- APIerSv1GetAccountActionTriggers = "APIerSv1.GetAccountActionTriggers"
- APIerSv1AddAccountActionTriggers = "APIerSv1.AddAccountActionTriggers"
- APIerSv1ResetAccountActionTriggers = "APIerSv1.ResetAccountActionTriggers"
- APIerSv1SetAccountActionTriggers = "APIerSv1.SetAccountActionTriggers"
- APIerSv1RemoveAccountActionTriggers = "APIerSv1.RemoveAccountActionTriggers"
- APIerSv1GetScheduledActions = "APIerSv1.GetScheduledActions"
- APIerSv1RemoveActionTiming = "APIerSv1.RemoveActionTiming"
- APIerSv1ComputeReverseDestinations = "APIerSv1.ComputeReverseDestinations"
- APIerSv1ComputeAccountActionPlans = "APIerSv1.ComputeAccountActionPlans"
- APIerSv1SetDestination = "APIerSv1.SetDestination"
- APIerSv1GetDataCost = "APIerSv1.GetDataCost"
- APIerSv1ReplayFailedPosts = "APIerSv1.ReplayFailedPosts"
- APIerSv1RemoveAccount = "APIerSv1.RemoveAccount"
- APIerSv1DebitUsage = "APIerSv1.DebitUsage"
- APIerSv1GetCacheStats = "APIerSv1.GetCacheStats"
- APIerSv1ReloadCache = "APIerSv1.ReloadCache"
- APIerSv1GetActionTriggers = "APIerSv1.GetActionTriggers"
- APIerSv1SetActionTrigger = "APIerSv1.SetActionTrigger"
- APIerSv1RemoveActionPlan = "APIerSv1.RemoveActionPlan"
- APIerSv1RemoveActions = "APIerSv1.RemoveActions"
- APIerSv1RemoveBalances = "APIerSv1.RemoveBalances"
- APIerSv1ReloadCdreConfig = "APIerSv1.ReloadCdreConfig"
- APIerSv1GetLoadHistory = "APIerSv1.GetLoadHistory"
- APIerSv1GetLoadIDs = "APIerSv1.GetLoadIDs"
- APIerSv1ExecuteScheduledActions = "APIerSv1.ExecuteScheduledActions"
- APIerSv1GetLoadTimes = "APIerSv1.GetLoadTimes"
- APIerSv1GetSharedGroup = "APIerSv1.GetSharedGroup"
- APIerSv1RemoveActionTrigger = "APIerSv1.RemoveActionTrigger"
- APIerSv1GetAccount = "APIerSv1.GetAccount"
-)
-
-// APIerSv1 TP APIs
-const (
- APIerSv1SetTPTiming = "APIerSv1.SetTPTiming"
- APIerSv1GetTPTiming = "APIerSv1.GetTPTiming"
- APIerSv1RemoveTPTiming = "APIerSv1.RemoveTPTiming"
- APIerSv1GetTPTimingIds = "APIerSv1.GetTPTimingIds"
- APIerSv1LoadTariffPlanFromStorDb = "APIerSv1.LoadTariffPlanFromStorDb"
- APIerSv1RemoveTPFromFolder = "APIerSv1.RemoveTPFromFolder"
-)
-
-// APIerSv2 APIs
-const (
- APIerSv2 = "APIerSv2"
- APIerSv2LoadTariffPlanFromFolder = "APIerSv2.LoadTariffPlanFromFolder"
- APIerSv2GetCDRs = "APIerSv2.GetCDRs"
- APIerSv2GetAccount = "APIerSv2.GetAccount"
- APIerSv2GetAccounts = "APIerSv2.GetAccounts"
- APIerSv2SetAccount = "APIerSv2.SetAccount"
- APIerSv2CountCDRs = "APIerSv2.CountCDRs"
- APIerSv2SetBalance = "APIerSv2.SetBalance"
- APIerSv2SetActions = "APIerSv2.SetActions"
- APIerSv2RemoveTPTiming = "APIerSv2.RemoveTPTiming"
- APIerSv2GetTPDestination = "APIerSv2.GetTPDestination"
- APIerSv2SetTPDestination = "APIerSv2.SetTPDestination"
- APIerSv2RemoveTPDestination = "APIerSv2.RemoveTPDestination"
- APIerSv2GetTPDestinationIDs = "APIerSv2.GetTPDestinationIDs"
- APIerSv2GetTPTiming = "APIerSv2.GetTPTiming"
- APIerSv2SetTPTiming = "APIerSv2.SetTPTiming"
- APIerSv2SetAccountActionTriggers = "APIerSv2.SetAccountActionTriggers"
- APIerSv2GetAccountActionTriggers = "APIerSv2.GetAccountActionTriggers"
- APIerSv2SetActionPlan = "APIerSv2.SetActionPlan"
- APIerSv2GetActions = "APIerSv2.GetActions"
- APIerSv2GetDestinations = "APIerSv2.GetDestinations"
- APIerSv2GetCacheStats = "APIerSv2.GetCacheStats"
- APIerSv2ExecuteAction = "APIerSv2.ExecuteAction"
- APIerSv2ResetAccountActionTriggers = "APIerSv2.ResetAccountActionTriggers"
- APIerSv2RemoveActions = "APIerSv2.RemoveActions"
-)
-
-const (
- ServiceManagerV1 = "ServiceManagerV1"
- ServiceManagerV1StartService = "ServiceManagerV1.StartService"
- ServiceManagerV1StopService = "ServiceManagerV1.StopService"
- ServiceManagerV1ServiceStatus = "ServiceManagerV1.ServiceStatus"
- ServiceManagerV1Ping = "ServiceManagerV1.Ping"
-)
-
-const (
- ConfigSv1 = "ConfigSv1"
- ConfigSv1GetJSONSection = "ConfigSv1.GetJSONSection"
- ConfigSv1ReloadConfigFromPath = "ConfigSv1.ReloadConfigFromPath"
- ConfigSv1ReloadConfigFromJSON = "ConfigSv1.ReloadConfigFromJSON"
-)
-
-const (
- RALsV1 = "RALsV1"
- RALsV1GetRatingPlansCost = "RALsV1.GetRatingPlansCost"
- RALsV1Ping = "RALsV1.Ping"
-)
-
-const (
- CoreS = "CoreS"
- CoreSv1 = "CoreSv1"
- CoreSv1Status = "CoreSv1.Status"
- CoreSv1Ping = "CoreSv1.Ping"
- CoreSv1Sleep = "CoreSv1.Sleep"
-)
-
-// SupplierS APIs
-const (
- SupplierSv1GetSuppliers = "SupplierSv1.GetSuppliers"
- SupplierSv1GetSupplierProfilesForEvent = "SupplierSv1.GetSupplierProfilesForEvent"
- SupplierSv1Ping = "SupplierSv1.Ping"
- APIerSv1GetSupplierProfile = "APIerSv1.GetSupplierProfile"
- APIerSv1GetSupplierProfileIDs = "APIerSv1.GetSupplierProfileIDs"
- APIerSv1RemoveSupplierProfile = "APIerSv1.RemoveSupplierProfile"
- APIerSv1SetSupplierProfile = "APIerSv1.SetSupplierProfile"
-)
-
-// AttributeS APIs
-const (
- APIerSv1SetAttributeProfile = "APIerSv1.SetAttributeProfile"
- APIerSv1GetAttributeProfile = "APIerSv1.GetAttributeProfile"
- APIerSv1GetAttributeProfileIDs = "APIerSv1.GetAttributeProfileIDs"
- APIerSv1RemoveAttributeProfile = "APIerSv1.RemoveAttributeProfile"
- APIerSv2SetAttributeProfile = "APIerSv2.SetAttributeProfile"
- AttributeSv1GetAttributeForEvent = "AttributeSv1.GetAttributeForEvent"
- AttributeSv1ProcessEvent = "AttributeSv1.ProcessEvent"
- AttributeSv1Ping = "AttributeSv1.Ping"
-)
-
-// ChargerS APIs
-const (
- ChargerSv1Ping = "ChargerSv1.Ping"
- ChargerSv1GetChargersForEvent = "ChargerSv1.GetChargersForEvent"
- ChargerSv1ProcessEvent = "ChargerSv1.ProcessEvent"
- APIerSv1GetChargerProfile = "APIerSv1.GetChargerProfile"
- APIerSv1RemoveChargerProfile = "APIerSv1.RemoveChargerProfile"
- APIerSv1SetChargerProfile = "APIerSv1.SetChargerProfile"
- APIerSv1GetChargerProfileIDs = "APIerSv1.GetChargerProfileIDs"
-)
-
-// ThresholdS APIs
-const (
- ThresholdSv1ProcessEvent = "ThresholdSv1.ProcessEvent"
- ThresholdSv1GetThreshold = "ThresholdSv1.GetThreshold"
- ThresholdSv1GetThresholdIDs = "ThresholdSv1.GetThresholdIDs"
- ThresholdSv1Ping = "ThresholdSv1.Ping"
- ThresholdSv1GetThresholdsForEvent = "ThresholdSv1.GetThresholdsForEvent"
- APIerSv1GetThresholdProfileIDs = "APIerSv1.GetThresholdProfileIDs"
- APIerSv1GetThresholdProfile = "APIerSv1.GetThresholdProfile"
- APIerSv1RemoveThresholdProfile = "APIerSv1.RemoveThresholdProfile"
- APIerSv1SetThresholdProfile = "APIerSv1.SetThresholdProfile"
-)
-
-// StatS APIs
-const (
- StatSv1ProcessEvent = "StatSv1.ProcessEvent"
- StatSv1GetQueueIDs = "StatSv1.GetQueueIDs"
- StatSv1GetQueueStringMetrics = "StatSv1.GetQueueStringMetrics"
- StatSv1GetQueueFloatMetrics = "StatSv1.GetQueueFloatMetrics"
- StatSv1Ping = "StatSv1.Ping"
- StatSv1GetStatQueuesForEvent = "StatSv1.GetStatQueuesForEvent"
- StatSv1GetStatQueue = "StatSv1.GetStatQueue"
- APIerSv1GetStatQueueProfile = "APIerSv1.GetStatQueueProfile"
- APIerSv1RemoveStatQueueProfile = "APIerSv1.RemoveStatQueueProfile"
- APIerSv1SetStatQueueProfile = "APIerSv1.SetStatQueueProfile"
- APIerSv1GetStatQueueProfileIDs = "APIerSv1.GetStatQueueProfileIDs"
-)
-
-// ResourceS APIs
-const (
- ResourceSv1AuthorizeResources = "ResourceSv1.AuthorizeResources"
- ResourceSv1GetResourcesForEvent = "ResourceSv1.GetResourcesForEvent"
- ResourceSv1AllocateResources = "ResourceSv1.AllocateResources"
- ResourceSv1ReleaseResources = "ResourceSv1.ReleaseResources"
- ResourceSv1Ping = "ResourceSv1.Ping"
- ResourceSv1GetResource = "ResourceSv1.GetResource"
- APIerSv1SetResourceProfile = "APIerSv1.SetResourceProfile"
- APIerSv1RemoveResourceProfile = "APIerSv1.RemoveResourceProfile"
- APIerSv1GetResourceProfile = "APIerSv1.GetResourceProfile"
- APIerSv1GetResourceProfileIDs = "APIerSv1.GetResourceProfileIDs"
-)
-
-// SessionS APIs
-const (
- SessionSv1AuthorizeEvent = "SessionSv1.AuthorizeEvent"
- SessionSv1AuthorizeEventWithDigest = "SessionSv1.AuthorizeEventWithDigest"
- SessionSv1InitiateSession = "SessionSv1.InitiateSession"
- SessionSv1InitiateSessionWithDigest = "SessionSv1.InitiateSessionWithDigest"
- SessionSv1UpdateSession = "SessionSv1.UpdateSession"
- SessionSv1SyncSessions = "SessionSv1.SyncSessions"
- SessionSv1TerminateSession = "SessionSv1.TerminateSession"
- SessionSv1ProcessCDR = "SessionSv1.ProcessCDR"
- SessionSv1ProcessMessage = "SessionSv1.ProcessMessage"
- SessionSv1ProcessEvent = "SessionSv1.ProcessEvent"
- SessionSv1DisconnectSession = "SessionSv1.DisconnectSession"
- SessionSv1GetActiveSessions = "SessionSv1.GetActiveSessions"
- SessionSv1GetActiveSessionsCount = "SessionSv1.GetActiveSessionsCount"
- SessionSv1ForceDisconnect = "SessionSv1.ForceDisconnect"
- SessionSv1GetPassiveSessions = "SessionSv1.GetPassiveSessions"
- SessionSv1GetPassiveSessionsCount = "SessionSv1.GetPassiveSessionsCount"
- SessionSv1SetPassiveSession = "SessionSv1.SetPassiveSession"
- SessionSv1Ping = "SessionSv1.Ping"
- SessionSv1GetActiveSessionIDs = "SessionSv1.GetActiveSessionIDs"
- SessionSv1RegisterInternalBiJSONConn = "SessionSv1.RegisterInternalBiJSONConn"
- SessionSv1ReplicateSessions = "SessionSv1.ReplicateSessions"
- SessionSv1ActivateSessions = "SessionSv1.ActivateSessions"
- SessionSv1DeactivateSessions = "SessionSv1.DeactivateSessions"
- SMGenericV1InitiateSession = "SMGenericV1.InitiateSession"
- SessionSv1Sleep = "SessionSv1.Sleep"
-)
-
-// Responder APIs
-const (
- Responder = "Responder"
- ResponderDebit = "Responder.Debit"
- ResponderRefundIncrements = "Responder.RefundIncrements"
- ResponderGetMaxSessionTime = "Responder.GetMaxSessionTime"
- ResponderMaxDebit = "Responder.MaxDebit"
- ResponderRefundRounding = "Responder.RefundRounding"
- ResponderGetCost = "Responder.GetCost"
- ResponderGetCostOnRatingPlans = "Responder.GetCostOnRatingPlans"
- ResponderGetMaxSessionTimeOnAccounts = "Responder.GetMaxSessionTimeOnAccounts"
- ResponderShutdown = "Responder.Shutdown"
- ResponderPing = "Responder.Ping"
-)
-
-// DispatcherS APIs
-const (
- DispatcherSv1Ping = "DispatcherSv1.Ping"
- DispatcherSv1GetProfileForEvent = "DispatcherSv1.GetProfileForEvent"
- DispatcherSv1Apier = "DispatcherSv1.Apier"
- DispatcherServicePing = "DispatcherService.Ping"
-)
-
-// AnalyzerS APIs
-const (
- AnalyzerSv1 = "AnalyzerSv1"
- AnalyzerSv1Ping = "AnalyzerSv1.Ping"
-)
-
-// LoaderS APIs
-const (
- LoaderSv1 = "LoaderSv1"
- LoaderSv1Load = "LoaderSv1.Load"
- LoaderSv1Remove = "LoaderSv1.Remove"
- LoaderSv1Ping = "LoaderSv1.Ping"
-)
-
-// CacheS APIs
-const (
- CacheSv1 = "CacheSv1"
- CacheSv1GetCacheStats = "CacheSv1.GetCacheStats"
- CacheSv1GetItemIDs = "CacheSv1.GetItemIDs"
- CacheSv1HasItem = "CacheSv1.HasItem"
- CacheSv1GetItemExpiryTime = "CacheSv1.GetItemExpiryTime"
- CacheSv1RemoveItem = "CacheSv1.RemoveItem"
- CacheSv1PrecacheStatus = "CacheSv1.PrecacheStatus"
- CacheSv1HasGroup = "CacheSv1.HasGroup"
- CacheSv1GetGroupItemIDs = "CacheSv1.GetGroupItemIDs"
- CacheSv1RemoveGroup = "CacheSv1.RemoveGroup"
- CacheSv1Clear = "CacheSv1.Clear"
- CacheSv1ReloadCache = "CacheSv1.ReloadCache"
- CacheSv1LoadCache = "CacheSv1.LoadCache"
- CacheSv1FlushCache = "CacheSv1.FlushCache"
- CacheSv1Ping = "CacheSv1.Ping"
-)
-
-// GuardianS APIs
-const (
- GuardianSv1 = "GuardianSv1"
- GuardianSv1RemoteLock = "GuardianSv1.RemoteLock"
- GuardianSv1RemoteUnlock = "GuardianSv1.RemoteUnlock"
- GuardianSv1Ping = "GuardianSv1.Ping"
-)
-
-// Cdrs APIs
-const (
- CDRsV1 = "CDRsV1"
- CDRsV1GetCDRsCount = "CDRsV1.GetCDRsCount"
- CDRsV1RateCDRs = "CDRsV1.RateCDRs"
- CDRsV1GetCDRs = "CDRsV1.GetCDRs"
- CDRsV1ProcessCDR = "CDRsV1.ProcessCDR"
- CDRsV1ProcessExternalCDR = "CDRsV1.ProcessExternalCDR"
- CDRsV1StoreSessionCost = "CDRsV1.StoreSessionCost"
- CDRsV1ProcessEvent = "CDRsV1.ProcessEvent"
- CDRsV1Ping = "CDRsV1.Ping"
- CDRsV2 = "CDRsV2"
- CDRsV2StoreSessionCost = "CDRsV2.StoreSessionCost"
- CdrsV2ProcessExternalCdr = "CdrsV2.ProcessExternalCdr"
- CdrsV2ProcessCdr = "CdrsV2.ProcessCdr"
-)
-
-// Scheduler
-const (
- SchedulerSv1 = "SchedulerSv1"
- SchedulerSv1Ping = "SchedulerSv1.Ping"
- SchedulerSv1Reload = "SchedulerSv1.Reload"
-)
-
-// cgr_ variables
-const (
- CGR_ACCOUNT = "cgr_account"
- CGR_SUPPLIER = "cgr_supplier"
- CGR_DESTINATION = "cgr_destination"
- CGR_SUBJECT = "cgr_subject"
- CGR_CATEGORY = "cgr_category"
- CGR_REQTYPE = "cgr_reqtype"
- CGR_TENANT = "cgr_tenant"
- CGR_PDD = "cgr_pdd"
- CGR_DISCONNECT_CAUSE = "cgr_disconnectcause"
- CGR_COMPUTELCR = "cgr_computelcr"
- CGR_SUPPLIERS = "cgr_suppliers"
- CGRFlags = "cgr_flags"
-)
-
-// CSV file name
-const (
- TimingsCsv = "Timings.csv"
- DestinationsCsv = "Destinations.csv"
- RatesCsv = "Rates.csv"
- DestinationRatesCsv = "DestinationRates.csv"
- RatingPlansCsv = "RatingPlans.csv"
- RatingProfilesCsv = "RatingProfiles.csv"
- SharedGroupsCsv = "SharedGroups.csv"
- ActionsCsv = "Actions.csv"
- ActionPlansCsv = "ActionPlans.csv"
- ActionTriggersCsv = "ActionTriggers.csv"
- AccountActionsCsv = "AccountActions.csv"
- ResourcesCsv = "Resources.csv"
- StatsCsv = "Stats.csv"
- ThresholdsCsv = "Thresholds.csv"
- FiltersCsv = "Filters.csv"
- SuppliersCsv = "Suppliers.csv"
- AttributesCsv = "Attributes.csv"
- ChargersCsv = "Chargers.csv"
- DispatcherProfilesCsv = "DispatcherProfiles.csv"
- DispatcherHostsCsv = "DispatcherHosts.csv"
-)
-
-// Table Name
-const (
- TBLTPTimings = "tp_timings"
- TBLTPDestinations = "tp_destinations"
- TBLTPRates = "tp_rates"
- TBLTPDestinationRates = "tp_destination_rates"
- TBLTPRatingPlans = "tp_rating_plans"
- TBLTPRateProfiles = "tp_rating_profiles"
- TBLTPSharedGroups = "tp_shared_groups"
- TBLTPActions = "tp_actions"
- TBLTPActionPlans = "tp_action_plans"
- TBLTPActionTriggers = "tp_action_triggers"
- TBLTPAccountActions = "tp_account_actions"
- TBLTPResources = "tp_resources"
- TBLTPStats = "tp_stats"
- TBLTPThresholds = "tp_thresholds"
- TBLTPFilters = "tp_filters"
- SessionCostsTBL = "session_costs"
- CDRsTBL = "cdrs"
- TBLTPSuppliers = "tp_suppliers"
- TBLTPAttributes = "tp_attributes"
- TBLTPChargers = "tp_chargers"
- TBLVersions = "versions"
- OldSMCosts = "sm_costs"
- TBLTPDispatchers = "tp_dispatcher_profiles"
- TBLTPDispatcherHosts = "tp_dispatcher_hosts"
-)
-
-// Cache Name
-const (
- CacheDestinations = "*destinations"
- CacheReverseDestinations = "*reverse_destinations"
- CacheRatingPlans = "*rating_plans"
- CacheRatingProfiles = "*rating_profiles"
- CacheActions = "*actions"
- CacheActionPlans = "*action_plans"
- CacheAccountActionPlans = "*account_action_plans"
- CacheActionTriggers = "*action_triggers"
- CacheSharedGroups = "*shared_groups"
- CacheResources = "*resources"
- CacheResourceProfiles = "*resource_profiles"
- CacheTimings = "*timings"
- CacheEventResources = "*event_resources"
- CacheStatQueueProfiles = "*statqueue_profiles"
- CacheStatQueues = "*statqueues"
- CacheThresholdProfiles = "*threshold_profiles"
- CacheThresholds = "*thresholds"
- CacheFilters = "*filters"
- CacheSupplierProfiles = "*supplier_profiles"
- CacheAttributeProfiles = "*attribute_profiles"
- CacheChargerProfiles = "*charger_profiles"
- CacheDispatcherProfiles = "*dispatcher_profiles"
- CacheDispatcherHosts = "*dispatcher_hosts"
- CacheDispatchers = "*dispatchers"
- CacheDispatcherRoutes = "*dispatcher_routes"
- CacheResourceFilterIndexes = "*resource_filter_indexes"
- CacheStatFilterIndexes = "*stat_filter_indexes"
- CacheThresholdFilterIndexes = "*threshold_filter_indexes"
- CacheSupplierFilterIndexes = "*supplier_filter_indexes"
- CacheAttributeFilterIndexes = "*attribute_filter_indexes"
- CacheChargerFilterIndexes = "*charger_filter_indexes"
- CacheDispatcherFilterIndexes = "*dispatcher_filter_indexes"
- CacheReverseFilterIndexes = "*reverse_filter_indexes"
- CacheDiameterMessages = "*diameter_messages"
- CacheRPCResponses = "*rpc_responses"
- CacheClosedSessions = "*closed_sessions"
- MetaPrecaching = "*precaching"
- MetaReady = "*ready"
- CacheLoadIDs = "*load_ids"
- CacheAccounts = "*accounts"
- CacheRPCConnections = "*rpc_connections"
- CacheCDRIDs = "*cdr_ids"
- CacheRatingProfilesTmp = "*tmp_rating_profiles"
- CacheReplicationHosts = "*replication_hosts"
-)
-
-// Prefix for indexing
-const (
- ResourceFilterIndexes = "rfi_"
- StatFilterIndexes = "sfi_"
- ThresholdFilterIndexes = "tfi_"
- SupplierFilterIndexes = "spi_"
- AttributeFilterIndexes = "afi_"
- ChargerFilterIndexes = "cfi_"
- DispatcherFilterIndexes = "dfi_"
- ActionPlanIndexes = "api_"
- ReverseFilterIndexes = "fii_"
-)
-
-// Agents
-const (
- KamailioAgent = "KamailioAgent"
- RadiusAgent = "RadiusAgent"
- DiameterAgent = "DiameterAgent"
- FreeSWITCHAgent = "FreeSWITCHAgent"
- AsteriskAgent = "AsteriskAgent"
- HTTPAgent = "HTTPAgent"
-)
-
-// Poster
-const (
- SQSPoster = "SQSPoster"
- S3Poster = "S3Poster"
- AWSRegion = "aws_region"
- AWSKey = "aws_key"
- AWSSecret = "aws_secret"
- KafkaTopic = "topic"
- KafkaGroupID = "group_id"
- KafkaMaxWait = "max_wait"
-)
-
-// Google_API
-const (
- MetaGoogleAPI = "*gapi"
- GoogleConfigDirName = ".gapi"
- GoogleCredentialsFileName = "credentials.json"
- GoogleTokenFileName = "token.json"
-)
-
-// StorDB
-var (
- PostgressSSLModeDisable = "disable"
- PostgressSSLModeAllow = "allow"
- PostgressSSLModePrefer = "prefer"
- PostgressSSLModeRequire = "require"
- PostgressSSLModeVerifyCa = "verify-ca"
- PostgressSSLModeVerifyFull = "verify-full"
-)
-
-// GeneralCfg
-const (
- NodeIDCfg = "node_id"
- LoggerCfg = "logger"
- LogLevelCfg = "log_level"
- HttpSkipTlsVerifyCfg = "http_skip_tls_verify"
- RoundingDecimalsCfg = "rounding_decimals"
- DBDataEncodingCfg = "dbdata_encoding"
- TpExportPathCfg = "tpexport_dir"
- PosterAttemptsCfg = "poster_attempts"
- FailedPostsDirCfg = "failed_posts_dir"
- FailedPostsTTLCfg = "failed_posts_ttl"
- DefaultReqTypeCfg = "default_request_type"
- DefaultCategoryCfg = "default_category"
- DefaultTenantCfg = "default_tenant"
- DefaultTimezoneCfg = "default_timezone"
- DefaultCachingCfg = "default_caching"
- ConnectAttemptsCfg = "connect_attempts"
- ReconnectsCfg = "reconnects"
- ConnectTimeoutCfg = "connect_timeout"
- ReplyTimeoutCfg = "reply_timeout"
- LockingTimeoutCfg = "locking_timeout"
- DigestSeparatorCfg = "digest_separator"
- DigestEqualCfg = "digest_equal"
- RSRSepCfg = "rsr_separator"
- MaxParallelConnsCfg = "max_parallel_conns"
- ConcurrentRequestsCfg = "concurrent_requests"
- ConcurrentStrategyCfg = "concurrent_strategy"
-)
-
-// StorDbCfg
-const (
- TypeCfg = "type"
- MaxOpenConnsCfg = "max_open_conns"
- MaxIdleConnsCfg = "max_idle_conns"
- ConnMaxLifetimeCfg = "conn_max_lifetime"
- StringIndexedFieldsCfg = "string_indexed_fields"
- PrefixIndexedFieldsCfg = "prefix_indexed_fields"
- QueryTimeoutCfg = "query_timeout"
- SSLModeCfg = "sslmode"
- ItemsCfg = "items"
-)
-
-// DataDbCfg
-const (
- DataDbTypeCfg = "db_type"
- DataDbHostCfg = "db_host"
- DataDbPortCfg = "db_port"
- DataDbNameCfg = "db_name"
- DataDbUserCfg = "db_user"
- DataDbPassCfg = "db_password"
- DataDbSentinelNameCfg = "redis_sentinel"
- RmtConnsCfg = "remote_conns"
- RplConnsCfg = "replication_conns"
- ReplicationFilteredCfg = "replication_filtered"
-)
-
-// ItemOpt
-const (
- RemoteCfg = "remote"
- ReplicateCfg = "replicate"
- TTLCfg = "ttl"
- LimitCfg = "limit"
- StaticTTLCfg = "static_ttl"
-)
-
-// Tls
-const (
- ServerCerificateCfg = "server_certificate"
- ServerKeyCfg = "server_key"
- ServerPolicyCfg = "server_policy"
- ServerNameCfg = "server_name"
- ClientCerificateCfg = "client_certificate"
- ClientKeyCfg = "client_key"
- CaCertificateCfg = "ca_certificate"
-)
-
-// ListenCfg
-const (
- RPCJSONListenCfg = "rpc_json"
- RPCGOBListenCfg = "rpc_gob"
- HTTPListenCfg = "http"
- RPCJSONTLSListenCfg = "rpc_json_tls"
- RPCGOBTLSListenCfg = "rpc_gob_tls"
- HTTPTLSListenCfg = "http_tls"
-)
-
-// HTTPCfg
-const (
- HTTPJsonRPCURLCfg = "json_rpc_url"
- HTTPWSURLCfg = "ws_url"
- HTTPFreeswitchCDRsURLCfg = "freeswitch_cdrs_url"
- HTTPCDRsURLCfg = "http_cdrs"
- HTTPUseBasicAuthCfg = "use_basic_auth"
- HTTPAuthUsersCfg = "auth_users"
-)
-
-// FilterSCfg
-const (
- StatSConnsCfg = "stats_conns"
- ResourceSConnsCfg = "resources_conns"
- ApierSConnsCfg = "apiers_conns"
-)
-
-// RalsCfg
-const (
- EnabledCfg = "enabled"
- ThresholdSConnsCfg = "thresholds_conns"
- CacheSConnsCfg = "caches_conns"
- RpSubjectPrefixMatchingCfg = "rp_subject_prefix_matching"
- RemoveExpiredCfg = "remove_expired"
- MaxComputedUsageCfg = "max_computed_usage"
- BalanceRatingSubjectCfg = "balance_rating_subject"
- MaxIncrementsCfg = "max_increments"
-)
-
-// SchedulerCfg
-const (
- CDRsConnsCfg = "cdrs_conns"
- FiltersCfg = "filters"
-)
-
-// CdrsCfg
-const (
- ExtraFieldsCfg = "extra_fields"
- StoreCdrsCfg = "store_cdrs"
- SMCostRetriesCfg = "session_cost_retries"
- ChargerSConnsCfg = "chargers_conns"
- AttributeSConnsCfg = "attributes_conns"
- OnlineCDRExportsCfg = "online_cdr_exports"
-)
-
-// SessionSCfg
-const (
- ListenBijsonCfg = "listen_bijson"
- RALsConnsCfg = "rals_conns"
- ResSConnsCfg = "resources_conns"
- ThreshSConnsCfg = "thresholds_conns"
- SupplSConnsCfg = "suppliers_conns"
- AttrSConnsCfg = "attributes_conns"
- ReplicationConnsCfg = "replication_conns"
- DebitIntervalCfg = "debit_interval"
- StoreSCostsCfg = "store_session_costs"
- SessionTTLCfg = "session_ttl"
- SessionTTLMaxDelayCfg = "session_ttl_max_delay"
- SessionTTLLastUsedCfg = "session_ttl_last_used"
- SessionTTLUsageCfg = "session_ttl_usage"
- SessionTTLLastUsageCfg = "session_ttl_last_usage"
- SessionIndexesCfg = "session_indexes"
- ClientProtocolCfg = "client_protocol"
- ChannelSyncIntervalCfg = "channel_sync_interval"
- TerminateAttemptsCfg = "terminate_attempts"
- AlterableFieldsCfg = "alterable_fields"
- MinDurLowBalanceCfg = "min_dur_low_balance"
- DefaultUsageCfg = "default_usage"
-)
-
-// FsAgentCfg
-const (
- SessionSConnsCfg = "sessions_conns"
- SubscribeParkCfg = "subscribe_park"
- CreateCdrCfg = "create_cdr"
- LowBalanceAnnFileCfg = "low_balance_ann_file"
- EmptyBalanceContextCfg = "empty_balance_context"
- EmptyBalanceAnnFileCfg = "empty_balance_ann_file"
- MaxWaitConnectionCfg = "max_wait_connection"
- EventSocketConnsCfg = "event_socket_conns"
-)
-
-// From Config
-const (
- AddressCfg = "address"
- Password = "password"
- AliasCfg = "alias"
-
- // KamAgentCfg
- EvapiConnsCfg = "evapi_conns"
- TimezoneCfg = "timezone"
- TimezoneCfgC = "Timezone"
-
- // AsteriskConnCfg
- UserCf = "user"
-
- // AsteriskAgentCfg
- CreateCDRCfg = "create_cdr"
- AsteriskConnsCfg = "asterisk_conns"
-
- // DiameterAgentCfg
- ListenNetCfg = "listen_net"
- ListenCfg = "listen"
- DictionariesPathCfg = "dictionaries_path"
- OriginHostCfg = "origin_host"
- OriginRealmCfg = "origin_realm"
- VendorIdCfg = "vendor_id"
- ProductNameCfg = "product_name"
- ConcurrentReqsCfg = "concurrent_requests"
- SyncedConnReqsCfg = "synced_conn_requests"
- ASRTemplateCfg = "asr_template"
- RARTemplateCfg = "rar_template"
- ForcedDisconnectCfg = "forced_disconnect"
- TemplatesCfg = "templates"
- RequestProcessorsCfg = "request_processors"
-
- // RequestProcessor
- RequestFieldsCfg = "request_fields"
- ReplyFieldsCfg = "reply_fields"
-
- // RadiusAgentCfg
- ListenAuthCfg = "listen_auth"
- ListenAcctCfg = "listen_acct"
- ClientSecretsCfg = "client_secrets"
- ClientDictionariesCfg = "client_dictionaries"
-
- // AttributeSCfg
- IndexedSelectsCfg = "indexed_selects"
- ProcessRunsCfg = "process_runs"
- NestedFieldsCfg = "nested_fields"
-
- // ChargerSCfg
- StoreIntervalCfg = "store_interval"
-
- // StatSCfg
- StoreUncompressedLimitCfg = "store_uncompressed_limit"
-
- // Cache
- PartitionsCfg = "partitions"
- PrecacheCfg = "precache"
-
- // CdreCfg
- ExportFormatCfg = "export_format"
- ExportPathCfg = "export_path"
- AttributeSContextCfg = "attributes_context"
- SynchronousCfg = "synchronous"
- AttemptsCfg = "attempts"
-
- //LoaderSCfg
- IdCfg = "id"
- DryRunCfg = "dry_run"
- LockFileNameCfg = "lock_filename"
- TpInDirCfg = "tp_in_dir"
- TpOutDirCfg = "tp_out_dir"
- DataCfg = "data"
-
- DefaultRatioCfg = "default_ratio"
- ReadersCfg = "readers"
- PoolSize = "poolSize"
- Conns = "conns"
- FilenameCfg = "file_name"
- RequestPayloadCfg = "request_payload"
- ReplyPayloadCfg = "reply_payload"
- TransportCfg = "transport"
- StrategyCfg = "strategy"
- Dynaprepaid_actionplansCfg = "dynaprepaid_actionplans"
-)
-
-// FC Template
-const (
- TagCfg = "tag"
- TypeCf = "type"
- PathCfg = "path"
- ValueCfg = "value"
- WidthCfg = "width"
- StripCfg = "strip"
- PaddingCfg = "padding"
- MandatoryCfg = "mandatory"
- AttributeIDCfg = "attribute_id"
- NewBranchCfg = "new_branch"
- BlockerCfg = "blocker"
- BreakOnSuccessCfg = "break_on_success"
- Handler_id = "handler_id"
- LayoutCfg = "layout"
- CostShiftDigitsCfg = "cost_shift_digits"
- MaskDestIDCfg = "mask_destinationd_id"
- MaskLenCfg = "mask_length"
-)
-
-// SureTax
-const (
- UrlCfg = "url"
- ClientNumberCfg = "client_number"
- ValidationKeyCfg = "validation_key"
- BusinessUnitCfg = "business_unit"
- IncludeLocalCostCfg = "include_local_cost"
- ReturnFileCodeCfg = "return_file_code"
- ResponseGroupCfg = "response_group"
- ResponseTypeCfg = "response_type"
- RegulatoryCodeCfg = "regulatory_code"
- ClientTrackingCfg = "client_tracking"
- CustomerNumberCfg = "customer_number"
- OrigNumberCfg = "orig_number"
- TermNumberCfg = "term_number"
- BillToNumberCfg = "bill_to_number"
- ZipcodeCfg = "zipcode"
- Plus4Cfg = "plus4"
- P2PZipcodeCfg = "p2pzipcode"
- P2PPlus4Cfg = "p2pplus4"
- UnitsCfg = "units"
- UnitTypeCfg = "unit_type"
- TaxIncludedCfg = "tax_included"
- TaxSitusRuleCfg = "tax_situs_rule"
- TransTypeCodeCfg = "trans_type_code"
- SalesTypeCodeCfg = "sales_type_code"
- TaxExemptionCodeListCfg = "tax_exemption_code_list"
-)
-
-// LoaderCgrCfg
-const (
- TpIDCfg = "tpid"
- DataPathCfg = "data_path"
- DisableReverseCfg = "disable_reverse"
- FieldSeparatorCfg = "field_separator"
- CachesConnsCfg = "caches_conns"
- SchedulerConnsCfg = "scheduler_conns"
- GapiCredentialsCfg = "gapi_credentials"
- GapiTokenCfg = "gapi_token"
-)
-
-// MigratorCgrCfg
-const (
- OutDataDBTypeCfg = "out_datadb_type"
- OutDataDBHostCfg = "out_datadb_host"
- OutDataDBPortCfg = "out_datadb_port"
- OutDataDBNameCfg = "out_datadb_name"
- OutDataDBUserCfg = "out_datadb_user"
- OutDataDBPasswordCfg = "out_datadb_password"
- OutDataDBEncodingCfg = "out_datadb_encoding"
- OutDataDBRedisSentinelCfg = "out_datadb_redis_sentinel"
- OutStorDBTypeCfg = "out_stordb_type"
- OutStorDBHostCfg = "out_stordb_host"
- OutStorDBPortCfg = "out_stordb_port"
- OutStorDBNameCfg = "out_stordb_name"
- OutStorDBUserCfg = "out_stordb_user"
- OutStorDBPasswordCfg = "out_stordb_password"
- UsersFiltersCfg = "users_filters"
-)
-
-// MailerCfg
-const (
- MailerServerCfg = "server"
- MailerAuthUserCfg = "auth_user"
- MailerAuthPassCfg = "auth_password"
- MailerFromAddrCfg = "from_address"
-)
-
-// EventReaderCfg
-const (
- IDCfg = "id"
- RowLengthCfg = "row_length"
- FieldSepCfg = "field_separator"
- RunDelayCfg = "run_delay"
- SourcePathCfg = "source_path"
- ProcessedPathCfg = "processed_path"
- XmlRootPathCfg = "xml_root_path"
- TenantCfg = "tenant"
- FlagsCfg = "flags"
- FailedCallsPrefixCfg = "failed_calls_prefix"
- PartialRecordCacheCfg = "partial_record_cache"
- PartialCacheExpiryActionCfg = "partial_cache_expiry_action"
- FieldsCfg = "fields"
- CacheDumpFieldsCfg = "cache_dump_fields"
-)
-
-// CGRConfig
-const (
- CdreProfiles = "cdre" // from JSON
- LoaderCfg = "loaders" // from JSON
- HttpAgentCfg = "http_agent" // from JSON
- RpcConns = "rpc_conns" // from JSON
- GeneralCfg = "general" // from JSON
- DataDbCfg = "data_db" // from JSON
- StorDbCfg = "stor_db" // from JSON
- TlsCfg = "tls" // from JSON
- CacheCfg = "caches" // from JSON
- HttpCfg = "http" // from JSON
- FilterSCfg = "filters" // from JSON
- RalsCfg = "rals" // from JSON
- SchedulerCfg = "schedulers" // from JSON
- CdrsCfg = "cdrs" // from JSON
- SessionSCfg = "sessions" // from JSON
- FsAgentCfg = "freeswitch_agent" // from JSON
- KamAgentCfg = "kamailio_agent" // from JSON
- AsteriskAgentCfg = "asterisk_agent" // from JSON
- DiameterAgentCfg = "diameter_agent" // from JSON
- RadiusAgentCfg = "radius_agent" // from JSON
- DnsAgentCfg = "dns_agent" // from JSON
- AttributeSCfg = "attributes" // from JSON
- ChargerSCfg = "chargers" // from JSON
- ResourceSCfg = "resources" // from JSON
- StatsCfg = "stats" // from JSON
- ThresholdSCfg = "thresholds" // from JSON
- SupplierSCfg = "suppliers" // from JSON
- SureTaxCfg = "suretax" // from JSON
- DispatcherSCfg = "dispatchers" // from JSON
- LoaderCgrCfg = "loader" // from JSON
- MigratorCgrCfg = "migrator" // from JSON
- MailerCfg = "mailer" // from JSON
- AnalyzerSCfg = "analyzers" // from JSON
- Apier = "apiers" // from JSON
- ErsCfg = "ers" // from JSON
-
-)
-
-// Go type limits
-const (
- AbsoluteMaxUint = ^uint(0)
- AbsoluteMinUint = 0
- AbsoluteMaxInt = int(AbsoluteMaxUint >> 1)
- AbsoluteMinInt = -AbsoluteMaxInt - 1
- AbsoluteMaxDuration = time.Duration(AbsoluteMaxInt)
-)
-
-// Strip/Padding strategy
-var (
- // common
- MetaRight = "*right"
- MetaLeft = "*left"
- // only for strip
- MetaXRight = "*xright"
- MetaXLeft = "*xleft"
- // only for padding
- MetaZeroLeft = "*zeroleft"
-)
-
-func buildCacheInstRevPrefixes() {
- CachePrefixToInstance = make(map[string]string)
- for k, v := range CacheInstanceToPrefix {
- CachePrefixToInstance[v] = k
- }
-}
-
-func buildCacheIndexesToPrefix() {
- CacheIndexesToPrefix = make(map[string]string)
- for k, v := range PrefixToIndexCache {
- CacheIndexesToPrefix[v] = k
- }
-}
-
-func init() {
- buildCacheInstRevPrefixes()
- buildCacheIndexesToPrefix()
-}
-
-
-
/*
-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 utils
-
-import (
- "archive/zip"
- "bytes"
- "crypto/rand"
- "crypto/sha1"
- "encoding/gob"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "log"
- "math"
- math_rand "math/rand"
- "os"
- "path/filepath"
- "reflect"
- "regexp"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "github.com/cgrates/rpcclient"
-)
-
-var (
- startCGRateSTime time.Time
-
- rfc3339Rule = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.+$`)
- sqlRule = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$`)
- utcFormat = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}[T]\d{2}:\d{2}:\d{2}$`)
- gotimeRule = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.?\d*\s[+,-]\d+\s\w+$`)
- gotimeRule2 = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.?\d*\s[+,-]\d+\s[+,-]\d+$`)
- fsTimestamp = regexp.MustCompile(`^\d{16}$`)
- astTimestamp = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d*[+,-]\d+$`)
- unixTimestampRule = regexp.MustCompile(`^\d{10}$`)
- unixTimestampMilisecondsRule = regexp.MustCompile(`^\d{13}$`)
- unixTimestampNanosecondsRule = regexp.MustCompile(`^\d{19}$`)
- oneLineTimestampRule = regexp.MustCompile(`^\d{14}$`)
- oneSpaceTimestampRule = regexp.MustCompile(`^\d{2}\.\d{2}.\d{4}\s{1}\d{2}:\d{2}:\d{2}$`)
- eamonTimestampRule = regexp.MustCompile(`^\d{2}/\d{2}/\d{4}\s{1}\d{2}:\d{2}:\d{2}$`)
- broadsoftTimestampRule = regexp.MustCompile(`^\d{14}\.\d{3}`)
-)
-
-func init() {
- startCGRateSTime = time.Now()
- math_rand.Seed(startCGRateSTime.UnixNano())
-}
-
-// GetStartTime return the Start time of engine (in UNIX format)
-func GetStartTime() string {
- return startCGRateSTime.Format(time.UnixDate)
-}
-
-func NewCounter(start, limit int64) *Counter {
- return &Counter{
- value: start,
- limit: limit,
- }
-}
-
-type Counter struct {
- value, limit int64
- sync.Mutex
-}
-
-func (c *Counter) Next() int64 {
- c.Lock()
- defer c.Unlock()
- c.value += 1
- if c.limit > 0 && c.value > c.limit {
- c.value = 0
- }
- return c.value
-}
-
-func (c *Counter) Value() int64 {
- c.Lock()
- defer c.Unlock()
- return c.value
-}
-
-// Returns first non empty string out of vals. Useful to extract defaults
-func FirstNonEmpty(vals ...string) string {
- for _, val := range vals {
- if len(val) != 0 {
- return val
- }
- }
- return EmptyString
-}
-
-// Sha1 generate the SHA1 hash from any string
-func Sha1(attrs ...string) string {
- hasher := sha1.New()
- for _, attr := range attrs {
- hasher.Write([]byte(attr))
- }
- return fmt.Sprintf("%x", hasher.Sum(nil))
-}
-
-// helper function for uuid generation
-func GenUUID() string {
- b := make([]byte, 16)
- _, err := io.ReadFull(rand.Reader, b)
- if err != nil {
- log.Fatal(err)
- }
- b[6] = (b[6] & 0x0F) | 0x40
- b[8] = (b[8] &^ 0x40) | 0x80
- return fmt.Sprintf("%x-%x-%x-%x-%x", b[:4], b[4:6], b[6:8], b[8:10],
- b[10:])
-}
-
-// UUIDSha1Prefix generates a prefix of the sha1 applied to an UUID
-// prefix 8 is chosen since the probability of colision starts being minimal after 7 characters (see git commits)
-func UUIDSha1Prefix() string {
- return Sha1(GenUUID())[:7]
-}
-
-// Round return rounded version of x with prec precision.
-//
-// Special cases are:
-//
-// Round(±0) = ±0
-// Round(±Inf) = ±Inf
-// Round(NaN) = NaN
-func Round(x float64, prec int, method string) float64 {
- var rounder float64
- maxPrec := 7 // define a max precison to cut float errors
- if maxPrec < prec {
- maxPrec = prec
- }
- pow := math.Pow(10, float64(prec))
- intermed := x * pow
- _, frac := math.Modf(intermed)
-
- switch method {
- case ROUNDING_UP:
- if frac >= math.Pow10(-maxPrec) { // Max precision we go, rest is float chaos
- rounder = math.Ceil(intermed)
- } else {
- rounder = math.Floor(intermed)
- }
- case ROUNDING_DOWN:
- rounder = math.Floor(intermed)
- case ROUNDING_MIDDLE:
- if frac >= 0.5 {
- rounder = math.Ceil(intermed)
- } else {
- rounder = math.Floor(intermed)
- }
- default:
- rounder = intermed
- }
-
- return rounder / pow
-}
-
-func getAddDuration(tmStr string) (addDur time.Duration, err error) {
- eDurIdx := strings.Index(tmStr, "+")
- if eDurIdx == -1 {
- return
- }
- return time.ParseDuration(tmStr[eDurIdx+1:])
-}
-
-// ParseTimeDetectLayout returns the time from string
-func ParseTimeDetectLayout(tmStr string, timezone string) (time.Time, error) {
- tmStr = strings.TrimSpace(tmStr)
- var nilTime time.Time
- if len(tmStr) == 0 || tmStr == UNLIMITED {
- return nilTime, nil
- }
- loc, err := time.LoadLocation(timezone)
- if err != nil {
- return nilTime, err
- }
- switch {
- case tmStr == UNLIMITED || tmStr == "":
- // leave it at zero
- case tmStr == "*daily":
- return time.Now().AddDate(0, 0, 1), nil // add one day
- case tmStr == "*monthly":
- return time.Now().AddDate(0, 1, 0), nil // add one month
- case tmStr == "*yearly":
- return time.Now().AddDate(1, 0, 0), nil // add one year
- case strings.HasPrefix(tmStr, "*month_end"):
- expDate := GetEndOfMonth(time.Now())
- extraDur, err := getAddDuration(tmStr)
- if err != nil {
- return nilTime, err
- }
- expDate = expDate.Add(extraDur)
- return expDate, nil
- case strings.HasPrefix(tmStr, "*mo"): // add one month and extra duration
- extraDur, err := getAddDuration(tmStr)
- if err != nil {
- return nilTime, err
- }
- return time.Now().AddDate(0, 1, 0).Add(extraDur), nil
- case astTimestamp.MatchString(tmStr):
- return time.Parse("2006-01-02T15:04:05.999999999-0700", tmStr)
- case rfc3339Rule.MatchString(tmStr):
- return time.Parse(time.RFC3339, tmStr)
- case gotimeRule.MatchString(tmStr):
- return time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", tmStr)
- case gotimeRule2.MatchString(tmStr):
- return time.Parse("2006-01-02 15:04:05.999999999 -0700 -0700", tmStr)
- case sqlRule.MatchString(tmStr):
- return time.ParseInLocation("2006-01-02 15:04:05", tmStr, loc)
- case fsTimestamp.MatchString(tmStr):
- if tmstmp, err := strconv.ParseInt(tmStr+"000", 10, 64); err != nil {
- return nilTime, err
- } else {
- return time.Unix(0, tmstmp).In(loc), nil
- }
- case unixTimestampRule.MatchString(tmStr):
- if tmstmp, err := strconv.ParseInt(tmStr, 10, 64); err != nil {
- return nilTime, err
- } else {
- return time.Unix(tmstmp, 0).In(loc), nil
- }
- case unixTimestampMilisecondsRule.MatchString(tmStr):
- if tmstmp, err := strconv.ParseInt(tmStr, 10, 64); err != nil {
- return nilTime, err
- } else {
- return time.Unix(0, tmstmp*int64(time.Millisecond)).In(loc), nil
- }
- case unixTimestampNanosecondsRule.MatchString(tmStr):
- if tmstmp, err := strconv.ParseInt(tmStr, 10, 64); err != nil {
- return nilTime, err
- } else {
- return time.Unix(0, tmstmp).In(loc), nil
- }
- case tmStr == "0" || len(tmStr) == 0: // Time probably missing from request
- return nilTime, nil
- case oneLineTimestampRule.MatchString(tmStr):
- return time.ParseInLocation("20060102150405", tmStr, loc)
- case oneSpaceTimestampRule.MatchString(tmStr):
- return time.ParseInLocation("02.01.2006 15:04:05", tmStr, loc)
- case eamonTimestampRule.MatchString(tmStr):
- return time.ParseInLocation("02/01/2006 15:04:05", tmStr, loc)
- case broadsoftTimestampRule.MatchString(tmStr):
- return time.ParseInLocation("20060102150405.999", tmStr, loc)
- case tmStr == "*now":
- return time.Now(), nil
- case strings.HasPrefix(tmStr, "+"):
- tmStr = strings.TrimPrefix(tmStr, "+")
- if tmStrTmp, err := time.ParseDuration(tmStr); err != nil {
- return nilTime, err
- } else {
- return time.Now().Add(tmStrTmp), nil
- }
- case utcFormat.MatchString(tmStr):
- return time.ParseInLocation("2006-01-02T15:04:05", tmStr, loc)
-
- }
- return nilTime, errors.New("Unsupported time format")
-}
-
-// RoundDuration returns a number equal or larger than the amount that exactly
-// is divisible to whole
-func RoundDuration(whole, amount time.Duration) time.Duration {
- a, w := float64(amount), float64(whole)
- if math.Mod(a, w) == 0 {
- return amount
- }
- return time.Duration((w - math.Mod(a, w) + a))
-}
-
-func SplitPrefix(prefix string, minLength int) []string {
- length := int(math.Max(float64(len(prefix)-(minLength-1)), 0))
- subs := make([]string, length)
- max := len(prefix)
- for i := 0; i < length; i++ {
- subs[i] = prefix[:max-i]
- }
- return subs
-}
-
-func CopyHour(src, dest time.Time) time.Time {
- if src.Hour() == 0 && src.Minute() == 0 && src.Second() == 0 {
- return src
- }
- return time.Date(dest.Year(), dest.Month(), dest.Day(), src.Hour(), src.Minute(), src.Second(), src.Nanosecond(), src.Location())
-}
-
-// Parses duration, considers s as time unit if not provided, seconds as float to specify subunits
-func ParseDurationWithSecs(durStr string) (d time.Duration, err error) {
- if durStr == "" {
- return
- }
- if _, err = strconv.ParseFloat(durStr, 64); err == nil { // Seconds format considered
- durStr += "s"
- }
- return time.ParseDuration(durStr)
-}
-
-// Parses duration, considers s as time unit if not provided, seconds as float to specify subunits
-func ParseDurationWithNanosecs(durStr string) (d time.Duration, err error) {
- if durStr == "" {
- return
- }
- if durStr == UNLIMITED {
- durStr = "-1"
- }
- if _, err = strconv.ParseFloat(durStr, 64); err == nil { // Seconds format considered
- durStr += "ns"
- }
- return time.ParseDuration(durStr)
-}
-
-// returns the minimum duration between the two
-func MinDuration(d1, d2 time.Duration) time.Duration {
- if d1 < d2 {
- return d1
- }
- return d2
-}
-
-// ParseZeroRatingSubject will parse the subject in the balance
-// returns duration if able to extract it from subject
-// returns error if not able to parse duration (ie: if ratingSubject is standard one)
-func ParseZeroRatingSubject(tor, rateSubj string, defaultRateSubj map[string]string) (time.Duration, error) {
- rateSubj = strings.TrimSpace(rateSubj)
- if rateSubj == "" || rateSubj == ANY {
- var hasToR bool
- if rateSubj, hasToR = defaultRateSubj[tor]; !hasToR {
- rateSubj = defaultRateSubj[META_ANY]
- }
- }
- if !strings.HasPrefix(rateSubj, ZERO_RATING_SUBJECT_PREFIX) {
- return 0, errors.New("malformed rating subject: " + rateSubj)
- }
- durStr := rateSubj[len(ZERO_RATING_SUBJECT_PREFIX):]
- if _, err := strconv.ParseFloat(durStr, 64); err == nil { // No time unit, postpend
- durStr += "ns"
- }
- return time.ParseDuration(durStr)
-}
-
-func ConcatenatedKey(keyVals ...string) string {
- return strings.Join(keyVals, CONCATENATED_KEY_SEP)
-}
-
-func SplitConcatenatedKey(key string) []string {
- return strings.Split(key, CONCATENATED_KEY_SEP)
-}
-
-func InfieldJoin(vals ...string) string {
- return strings.Join(vals, INFIELD_SEP)
-}
-
-func InfieldSplit(val string) []string {
- return strings.Split(val, INFIELD_SEP)
-}
-
-func Unzip(src, dest string) error {
- r, err := zip.OpenReader(src)
- if err != nil {
- return err
- }
- defer r.Close()
-
- for _, f := range r.File {
- rc, err := f.Open()
- if err != nil {
- return err
- }
- defer rc.Close()
-
- path := filepath.Join(dest, f.Name)
- if f.FileInfo().IsDir() {
- os.MkdirAll(path, f.Mode())
- } else {
- f, err := os.OpenFile(
- path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
- if err != nil {
- return err
- }
- defer f.Close()
-
- _, err = io.Copy(f, rc)
- if err != nil {
- return err
- }
- }
- }
-
- return nil
-}
-
-// Fib returns successive Fibonacci numbers.
-func Fib() func() int {
- a, b := 0, 1
- return func() int {
- if b > 0 { // only increment Fibonacci numbers while b doesn't overflow
- a, b = b, a+b
- }
- return a
- }
-}
-
-// FibDuration returns successive Fibonacci numbers as time.Duration with the
-// unit specified by durationUnit or maxDuration if it is exceeded
-func FibDuration(durationUnit, maxDuration time.Duration) func() time.Duration {
- fib := Fib()
- return func() time.Duration {
- fibNrAsDuration := time.Duration(fib())
- if fibNrAsDuration > (AbsoluteMaxDuration / durationUnit) { // check if the current fibonacci nr. in the sequence would exceed the absolute maximum duration if multiplied by the duration unit value
- fibNrAsDuration = AbsoluteMaxDuration
- } else {
- fibNrAsDuration *= durationUnit
- }
- if maxDuration > 0 && maxDuration < fibNrAsDuration {
- return maxDuration
- }
- return fibNrAsDuration
- }
-}
-
-// Utilities to provide pointers where we need to define ad-hoc
-func StringPointer(str string) *string {
- if str == ZERO {
- str = EmptyString
- return &str
- }
- return &str
-}
-
-func IntPointer(i int) *int {
- return &i
-}
-
-func Int64Pointer(i int64) *int64 {
- return &i
-}
-
-func Float64Pointer(f float64) *float64 {
- return &f
-}
-
-func BoolPointer(b bool) *bool {
- return &b
-}
-
-func StringMapPointer(sm StringMap) *StringMap {
- return &sm
-}
-
-func MapStringStringPointer(mp map[string]string) *map[string]string {
- return &mp
-}
-
-func TimePointer(t time.Time) *time.Time {
- return &t
-}
-
-func DurationPointer(d time.Duration) *time.Duration {
- return &d
-}
-
-func ToIJSON(v any) string {
- b, _ := json.MarshalIndent(v, "", " ")
- return string(b)
-}
-
-func ToJSON(v any) string {
- b, _ := json.Marshal(v)
- return string(b)
-}
-
-func LogFull(v any) {
- log.Print(ToIJSON(v))
-}
-
-// Simple object cloner, b should be a pointer towards a value into which we want to decode
-func Clone(a, b any) error {
- buff := new(bytes.Buffer)
- enc := gob.NewEncoder(buff)
- dec := gob.NewDecoder(buff)
- if err := enc.Encode(a); err != nil {
- return err
- }
- if err := dec.Decode(b); err != nil {
- return err
- }
- return nil
-}
-
-// Used as generic function logic for various fields
-
-// Attributes
-//
-// source - the base source
-// width - the field width
-// strip - if present it will specify the strip strategy, when missing strip will not be allowed
-// padding - if present it will specify the padding strategy to use, left, right, zeroleft, zeroright
-func FmtFieldWidth(fieldID, source string, width int, strip, padding string, mandatory bool) (string, error) {
- if mandatory && len(source) == 0 {
- return "", fmt.Errorf("Empty source value for fieldID: <%s>", fieldID)
- }
- if width == 0 { // Disable width processing if not defined
- return source, nil
- }
- if len(source) == width { // the source is exactly the maximum length
- return source, nil
- }
- if len(source) > width { //the source is bigger than allowed
- if len(strip) == 0 {
- return "", fmt.Errorf("Source %s is bigger than the width %d, no strip defied, fieldID: <%s>", source, width, fieldID)
- }
- if strip == MetaRight {
- return source[:width], nil
- } else if strip == MetaXRight {
- return source[:width-1] + "x", nil // Suffix with x to mark prefix
- } else if strip == MetaLeft {
- diffIndx := len(source) - width
- return source[diffIndx:], nil
- } else if strip == MetaXLeft { // Prefix one x to mark stripping
- diffIndx := len(source) - width
- return "x" + source[diffIndx+1:], nil
- }
- } else { //the source is smaller as the maximum allowed
- if len(padding) == 0 {
- return "", fmt.Errorf("Source %s is smaller than the width %d, no padding defined, fieldID: <%s>", source, width, fieldID)
- }
- var paddingFmt string
- switch padding {
- case MetaRight:
- paddingFmt = fmt.Sprintf("%%-%ds", width)
- case MetaLeft:
- paddingFmt = fmt.Sprintf("%%%ds", width)
- case MetaZeroLeft:
- paddingFmt = fmt.Sprintf("%%0%ds", width)
- }
- if len(paddingFmt) != 0 {
- return fmt.Sprintf(paddingFmt, source), nil
- }
- }
- return source, nil
-}
-
-// Returns the string representation of iface or error if not convertible
-func CastIfToString(iface any) (strVal string, casts bool) {
- switch rawVal := iface.(type) {
- case string:
- strVal = rawVal
- casts = true
- case int:
- strVal = strconv.Itoa(rawVal)
- casts = true
- case int64:
- strVal = strconv.FormatInt(rawVal, 10)
- casts = true
- case float64:
- strVal = strconv.FormatFloat(rawVal, 'f', -1, 64)
- casts = true
- case bool:
- strVal = strconv.FormatBool(rawVal)
- casts = true
- case []uint8:
- var byteVal []byte
- if byteVal, casts = iface.([]byte); casts {
- strVal = string(byteVal)
- }
- default: // Maybe we are lucky and the value converts to string
- strVal, casts = iface.(string)
- }
- return strVal, casts
-}
-
-func GetEndOfMonth(ref time.Time) time.Time {
- if ref.IsZero() {
- return time.Now()
- }
- year, month, _ := ref.Date()
- if month == time.December {
- year++
- month = time.January
- } else {
- month++
- }
- eom := time.Date(year, month, 1, 0, 0, 0, 0, ref.Location())
- return eom.Add(-time.Second)
-}
-
-// formats number in K,M,G, etc.
-func SizeFmt(num float64, suffix string) string {
- if suffix == EmptyString {
- suffix = "B"
- }
- for _, unit := range []string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"} {
- if math.Abs(num) < 1024.0 {
- return fmt.Sprintf("%3.1f%s%s", num, unit, suffix)
- }
- num /= 1024.0
- }
- return fmt.Sprintf("%.1f%s%s", num, "Yi", suffix)
-}
-
-func TimeIs0h(t time.Time) bool {
- return t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0
-}
-
-func ParseHierarchyPath(path string, sep string) HierarchyPath {
- if sep == EmptyString {
- for _, sep = range []string{"/", NestingSep} {
- if idx := strings.Index(path, sep); idx != -1 {
- break
- }
- }
- }
- path = strings.Trim(path, sep) // Need to strip if prefix of suffiy (eg: paths with /) so we can properly split
- return HierarchyPath(strings.Split(path, sep))
-}
-
-// HierarchyPath is used in various places to represent various path hierarchies (eg: in Diameter groups, XML trees)
-type HierarchyPath []string
-
-func (h HierarchyPath) AsString(sep string, prefix bool) string {
- if len(h) == 0 {
- return EmptyString
- }
- retStr := EmptyString
- for idx, itm := range h {
- if idx == 0 {
- if prefix {
- retStr += sep
- }
- } else {
- retStr += sep
- }
- retStr += itm
- }
- return retStr
-}
-
-// Mask a number of characters in the suffix of the destination
-func MaskSuffix(dest string, maskLen int) string {
- destLen := len(dest)
- if maskLen < 0 {
- return dest
- } else if maskLen > destLen {
- maskLen = destLen
- }
- dest = dest[:destLen-maskLen]
- for i := 0; i < maskLen; i++ {
- dest += MASK_CHAR
- }
- return dest
-}
-
-// Sortable Int64Slice
-type Int64Slice []int64
-
-func (slc Int64Slice) Len() int {
- return len(slc)
-}
-func (slc Int64Slice) Swap(i, j int) {
- slc[i], slc[j] = slc[j], slc[i]
-}
-func (slc Int64Slice) Less(i, j int) bool {
- return slc[i] < slc[j]
-}
-
-// CapitalizeErrorMessage returns the capitalized version of an error, useful in APIs
-func CapitalizedMessage(errMessage string) (capStr string) {
- capStr = strings.ToUpper(errMessage)
- capStr = strings.Replace(capStr, " ", "_", -1)
- return
-}
-
-func GetCGRVersion() (vers string, err error) {
- vers = fmt.Sprintf("%s@%s", CGRateS, VERSION)
- if GitLastLog == "" {
- return vers, nil
- }
- rdr := bytes.NewBufferString(GitLastLog)
- var commitHash string
- var commitDate time.Time
- for i := 0; i < 5; i++ { // read a maximum of 5 lines
- var ln string
- ln, err = rdr.ReadString('\n')
- if err != nil {
- return vers, fmt.Errorf("Building version - error: <%s> reading line from file", err.Error()) //or errorsNew()
- }
- if strings.HasPrefix(ln, "commit ") {
- commitSplt := strings.Split(ln, " ")
- if len(commitSplt) != 2 {
- return vers, fmt.Errorf("Building version - cannot extract commit hash")
- }
- commitHash = commitSplt[1]
- continue
- }
- if strings.HasPrefix(ln, "Date:") {
- dateSplt := strings.Split(ln, ": ")
- if len(dateSplt) != 2 {
- return vers, fmt.Errorf("Building version - cannot split commit date")
- }
- commitDate, err = time.Parse("Mon Jan 2 15:04:05 2006 -0700", strings.TrimSpace(dateSplt[1]))
- if err != nil {
- return vers, fmt.Errorf("Building version - error: <%s> compiling commit date", err.Error())
- }
- break
- }
- }
- if commitHash == "" || commitDate.IsZero() {
- return vers, fmt.Errorf("Cannot find commitHash or commitDate information")
- }
- //CGRateS@v0.10.1~dev-20200110075344-7572e7b11e00
- return fmt.Sprintf("%s@%s-%s-%s", CGRateS, VERSION, commitDate.UTC().Format("20060102150405"), commitHash[:12]), nil
-}
-
-func NewTenantID(tntID string) *TenantID {
- if !strings.Contains(tntID, CONCATENATED_KEY_SEP) { // no :, ID without Tenant
- return &TenantID{ID: tntID}
- }
- tIDSplt := strings.Split(tntID, CONCATENATED_KEY_SEP)
- return &TenantID{Tenant: tIDSplt[0], ID: ConcatenatedKey(tIDSplt[1:]...)}
-}
-
-type TenantArg struct {
- Tenant string
-}
-
-type TenantArgWithPaginator struct {
- TenantArg
- Paginator
-}
-
-type TenantWithArgDispatcher struct {
- *TenantArg
- *ArgDispatcher
-}
-
-type TenantID struct {
- Tenant string
- ID string
-}
-
-type TenantIDWithArgDispatcher struct {
- *TenantID
- *ArgDispatcher
-}
-
-func (tID *TenantID) TenantID() string {
- return ConcatenatedKey(tID.Tenant, tID.ID)
-}
-
-type TenantIDWithCache struct {
- Tenant string
- ID string
- Cache *string
-}
-
-func (tID *TenantIDWithCache) TenantID() string {
- return ConcatenatedKey(tID.Tenant, tID.ID)
-}
-
-// RPCCall is a generic method calling RPC on a struct instance
-// serviceMethod is assumed to be in the form InstanceV1.Method
-// where V1Method will become RPC method called on instance
-func RPCCall(inst any, serviceMethod string, args any, reply any) error {
- methodSplit := strings.Split(serviceMethod, ".")
- if len(methodSplit) != 2 {
- return rpcclient.ErrUnsupporteServiceMethod
- }
- method := reflect.ValueOf(inst).MethodByName(
- strings.ToUpper(methodSplit[0][len(methodSplit[0])-2:]) + methodSplit[1])
- if !method.IsValid() {
- return rpcclient.ErrUnsupporteServiceMethod
- }
- params := []reflect.Value{reflect.ValueOf(args), reflect.ValueOf(reply)}
- ret := method.Call(params)
- if len(ret) != 1 {
- return ErrServerError
- }
- if ret[0].Interface() == nil {
- return nil
- }
- err, ok := ret[0].Interface().(error)
- if !ok {
- return ErrServerError
- }
- return err
-}
-
-// ApierRPCCall implements generic RPCCall for APIer instances
-func APIerRPCCall(inst any, serviceMethod string, args any, reply any) error {
- methodSplit := strings.Split(serviceMethod, ".")
- if len(methodSplit) != 2 {
- return rpcclient.ErrUnsupporteServiceMethod
- }
- method := reflect.ValueOf(inst).MethodByName(methodSplit[1])
- if !method.IsValid() {
- return rpcclient.ErrUnsupporteServiceMethod
- }
- params := []reflect.Value{reflect.ValueOf(args), reflect.ValueOf(reply)}
- ret := method.Call(params)
- if len(ret) != 1 {
- return ErrServerError
- }
- if ret[0].Interface() == nil {
- return nil
- }
- err, ok := ret[0].Interface().(error)
- if !ok {
- return ErrServerError
- }
- return err
-}
-
-// CachedRPCResponse is used to cache a RPC response
-type CachedRPCResponse struct {
- Result any
- Error error
-}
-
-func ReverseString(s string) string {
- r := []rune(s)
- for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
- r[i], r[j] = r[j], r[i]
- }
- return string(r)
-}
-
-func GetUrlRawArguments(dialURL string) (out map[string]string) {
- out = make(map[string]string)
- idx := strings.IndexRune(dialURL, '?')
- if idx == -1 {
- return
- }
- strParams := dialURL[idx+1:]
- if len(strParams) == 0 {
- return
- }
- vecParams := strings.Split(strParams, "&")
- for _, paramPair := range vecParams {
- idx := strings.IndexRune(paramPair, '=')
- if idx == -1 {
- continue
- }
- out[paramPair[:idx]] = paramPair[idx+1:]
- }
- return
-}
-
-// WarnExecTime is used when we need to meassure the execution of specific functions
-// and warn when the total duration is higher than expected
-// should be usually called with defer, ie: defer WarnExecTime(time.Now(), "MyTestFunc", time.Duration(2*time.Second))
-func WarnExecTime(startTime time.Time, logID string, maxDur time.Duration) {
- totalDur := time.Since(startTime)
- if totalDur > maxDur {
- Logger.Warning(fmt.Sprintf("<%s> execution took: <%s>", logID, totalDur))
- }
-}
-
-// endchan := LongExecTimeDetector("mesaj", 5*time.Second)
-// defer func() { close(endchan) }()
-func LongExecTimeDetector(logID string, maxDur time.Duration) (endchan chan struct{}) {
- endchan = make(chan struct{}, 1)
- go func() {
- select {
- case <-time.After(maxDur):
- Logger.Warning(fmt.Sprintf("<%s> execution more than: <%s>", logID, maxDur))
- case <-endchan:
- }
- }()
- return
-}
-
-type GetFilterIndexesArg struct {
- CacheID string
- ItemIDPrefix string
- FilterType string
- FldNameVal map[string]string
-}
-
-type MatchFilterIndexArg struct {
- CacheID string
- ItemIDPrefix string
- FilterType string
- FieldName string
- FieldVal string
-}
-
-type SetFilterIndexesArg struct {
- CacheID string
- ItemIDPrefix string
- Indexes map[string]StringMap
-}
-
-func CastRPCErr(err error) error {
- if err != nil {
- if _, has := ErrMap[err.Error()]; has {
- return ErrMap[err.Error()]
- }
- }
- return err
-}
-
-// RandomInteger returns a random integer between min and max values
-func RandomInteger(min, max int) int {
- return math_rand.Intn(max-min) + min
-}
-
-
-
/*
-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 utils
-
-import (
- "encoding/hex"
- "fmt"
- "net"
- "strconv"
- "strings"
- "time"
-
- "github.com/nyaruka/phonenumbers"
-)
-
-// DataConverters groups together multiple converters,
-// executing optimized conversions
-type DataConverters []DataConverter
-
-// ConvertString converts from and to string
-func (dcs DataConverters) ConvertString(in string) (out string, err error) {
- outIface := any(in)
- for _, cnv := range dcs {
- if outIface, err = cnv.Convert(outIface); err != nil {
- return
- }
- }
- return IfaceAsString(outIface), nil
-}
-
-// DataConverter represents functions which should convert input into output
-type DataConverter interface {
- Convert(any) (any, error)
-}
-
-// NewDataConverter is a factory of converters
-func NewDataConverter(params string) (conv DataConverter, err error) {
- switch {
- case params == MetaDurationSeconds:
- return NewDurationSecondsConverter("")
- case params == MetaDurationNanoseconds:
- return NewDurationNanosecondsConverter("")
- case strings.HasPrefix(params, MetaRound):
- if len(params) == len(MetaRound) { // no extra params, defaults implied
- return NewRoundConverter("")
- }
- return NewRoundConverter(params[len(MetaRound)+1:])
- case strings.HasPrefix(params, MetaMultiply):
- if len(params) == len(MetaMultiply) { // no extra params, defaults implied
- return NewMultiplyConverter("")
- }
- return NewMultiplyConverter(params[len(MetaMultiply)+1:])
- case strings.HasPrefix(params, MetaDivide):
- if len(params) == len(MetaDivide) { // no extra params, defaults implied
- return NewDivideConverter("")
- }
- return NewDivideConverter(params[len(MetaDivide)+1:])
- case params == MetaDuration:
- return NewDurationConverter("")
- case params == MetaIP2Hex:
- return new(IP2HexConverter), nil
- case params == MetaString2Hex:
- return new(String2HexConverter), nil
- case strings.HasPrefix(params, MetaLibPhoneNumber):
- if len(params) == len(MetaLibPhoneNumber) {
- return NewPhoneNumberConverter("")
- }
- return NewPhoneNumberConverter(params[len(MetaLibPhoneNumber)+1:])
- default:
- return nil, fmt.Errorf("unsupported converter definition: <%s>", params)
- }
-}
-
-func NewDataConverterMustCompile(params string) (conv DataConverter) {
- var err error
- if conv, err = NewDataConverter(params); err != nil {
- panic(fmt.Sprintf("parsing: <%s>, error: %s", params, err.Error()))
- }
- return
-}
-
-func NewDurationSecondsConverter(params string) (hdlr DataConverter, err error) {
- return new(DurationSecondsConverter), nil
-}
-
-// DurationSecondsConverter converts duration into seconds encapsulated in float64
-type DurationSecondsConverter struct{}
-
-func (mS *DurationSecondsConverter) Convert(in any) (
- out any, err error) {
- var inDur time.Duration
- if inDur, err = IfaceAsDuration(in); err != nil {
- return nil, err
- }
- out = inDur.Seconds()
- return
-}
-
-func NewDurationNanosecondsConverter(params string) (
- hdlr DataConverter, err error) {
- return new(DurationNanosecondsConverter), nil
-}
-
-// DurationNanosecondsConverter converts duration into nanoseconds encapsulated in int64
-type DurationNanosecondsConverter struct{}
-
-func (mS *DurationNanosecondsConverter) Convert(in any) (
- out any, err error) {
- var inDur time.Duration
- if inDur, err = IfaceAsDuration(in); err != nil {
- return nil, err
- }
- out = inDur.Nanoseconds()
- return
-}
-
-func NewRoundConverter(params string) (hdlr DataConverter, err error) {
- rc := new(RoundConverter)
- var paramsSplt []string
- if params != EmptyString {
- paramsSplt = strings.Split(params, InInFieldSep)
- }
- switch len(paramsSplt) {
- case 0:
- rc.Method = ROUNDING_MIDDLE
- case 1:
- if rc.Decimals, err = strconv.Atoi(paramsSplt[0]); err != nil {
- return nil, fmt.Errorf("%s converter needs integer as decimals, have: <%s>",
- MetaRound, paramsSplt[0])
- }
- rc.Method = ROUNDING_MIDDLE
- case 2:
- rc.Method = paramsSplt[1]
- if rc.Decimals, err = strconv.Atoi(paramsSplt[0]); err != nil {
- return nil, fmt.Errorf("%s converter needs integer as decimals, have: <%s>",
- MetaRound, paramsSplt[0])
- }
- default:
- return nil, fmt.Errorf("unsupported %s converter parameters: <%s>",
- MetaRound, params)
- }
- return rc, nil
-}
-
-// RoundConverter will round floats
-type RoundConverter struct {
- Decimals int
- Method string
-}
-
-func (rnd *RoundConverter) Convert(in any) (out any, err error) {
- var inFloat float64
- if inFloat, err = IfaceAsFloat64(in); err != nil {
- return
- }
- out = Round(inFloat, rnd.Decimals, rnd.Method)
- return
-}
-
-func NewMultiplyConverter(constructParams string) (hdlr DataConverter, err error) {
- if constructParams == EmptyString {
- return nil, ErrMandatoryIeMissingNoCaps
- }
- var val float64
- if val, err = strconv.ParseFloat(constructParams, 64); err != nil {
- return
- }
- return &MultiplyConverter{Value: val}, nil
-}
-
-// MultiplyConverter multiplies input with value in params
-// encapsulates the output as float64 value
-type MultiplyConverter struct {
- Value float64
-}
-
-func (m *MultiplyConverter) Convert(in any) (out any, err error) {
- var inFloat64 float64
- if inFloat64, err = IfaceAsFloat64(in); err != nil {
- return nil, err
- }
- out = inFloat64 * m.Value
- return
-}
-
-func NewDivideConverter(constructParams string) (hdlr DataConverter, err error) {
- if constructParams == "" {
- return nil, ErrMandatoryIeMissingNoCaps
- }
- var val float64
- if val, err = strconv.ParseFloat(constructParams, 64); err != nil {
- return
- }
- return &DivideConverter{Value: val}, nil
-}
-
-// DivideConverter divides input with value in params
-// encapsulates the output as float64 value
-type DivideConverter struct {
- Value float64
-}
-
-func (m *DivideConverter) Convert(in any) (out any, err error) {
- var inFloat64 float64
- if inFloat64, err = IfaceAsFloat64(in); err != nil {
- return nil, err
- }
- out = inFloat64 / m.Value
- return
-}
-
-func NewDurationConverter(params string) (hdlr DataConverter, err error) {
- return new(DurationConverter), nil
-}
-
-// DurationConverter converts duration into seconds encapsulated in float64
-type DurationConverter struct{}
-
-func (mS *DurationConverter) Convert(in any) (
- out any, err error) {
- return IfaceAsDuration(in)
-}
-
-// NewPhoneNumberConverter create a new phoneNumber converter
-// If the format isn't specify by default we use NATIONAL
-// Possible fromats are : E164(0) , INTERNATIONAL(1) , NATIONAL(2) ,RFC3966(3)
-// Also ContryCode needs to be specified
-func NewPhoneNumberConverter(params string) (
- pbDC DataConverter, err error) {
- lc := new(PhoneNumberConverter)
- var paramsSplt []string
- if params != EmptyString {
- paramsSplt = strings.Split(params, InInFieldSep)
- }
- switch len(paramsSplt) {
- case 2:
- lc.CountryCode = paramsSplt[0]
- frm, err := strconv.Atoi(paramsSplt[1])
- if err != nil {
- return nil, err
- }
- lc.Format = phonenumbers.PhoneNumberFormat(frm)
- case 1:
- lc.CountryCode = paramsSplt[0]
- lc.Format = 2
- default:
- return nil, fmt.Errorf("unsupported %s converter parameters: <%s>",
- MetaLibPhoneNumber, params)
- }
- return lc, nil
-}
-
-// PhoneNumberConverter converts
-type PhoneNumberConverter struct {
- CountryCode string
- Format phonenumbers.PhoneNumberFormat
-}
-
-func (lc *PhoneNumberConverter) Convert(in any) (out any, err error) {
- num, err := phonenumbers.Parse(IfaceAsString(in), lc.CountryCode)
- if err != nil {
- return nil, err
- }
- return phonenumbers.Format(num, lc.Format), nil
-}
-
-// HexConvertor will round floats
-type IP2HexConverter struct{}
-
-func (*IP2HexConverter) Convert(in any) (out any, err error) {
- var ip net.IP
- switch val := in.(type) {
- case string:
- ip = net.ParseIP(val)
- case net.IP:
- ip = val
- default:
- src := IfaceAsString(in)
- ip = net.ParseIP(src)
- }
-
- hx := hex.EncodeToString([]byte(ip))
- if len(hx) < 8 {
- return hx, nil
- }
- return "0x" + string([]byte(hx)[len(hx)-8:]), nil
-}
-
-// String2HexConverter will transform the string to hex
-type String2HexConverter struct{}
-
-// Convert implements DataConverter interface
-func (*String2HexConverter) Convert(in any) (o any, err error) {
- var out string
- if out = hex.EncodeToString([]byte(IfaceAsString(in))); len(out) == 0 {
- o = out
- return
- }
- o = "0x" + out
- return
-}
-
-
-
/*
-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 utils
-
-import (
- "net"
- "strings"
-)
-
-// posible NMType
-const (
- NMDataType NMType = iota
- NMMapType
- NMSliceType
-)
-
-// DataProvider is a data source from multiple formats
-type DataProvider interface {
- String() string // printable version of data
- FieldAsInterface(fldPath []string) (any, error)
- FieldAsString(fldPath []string) (string, error) // remove this
- RemoteHost() net.Addr
-}
-
-// NavigableMapper is the interface supported by replies convertible to CGRReply
-type NavigableMapper interface {
- AsNavigableMap() NavigableMap2
-}
-
-// DPDynamicInterface returns the value of the field if the path is dynamic
-func DPDynamicInterface(dnVal string, dP DataProvider) (any, error) {
- if strings.HasPrefix(dnVal, DynamicDataPrefix) {
- dnVal = strings.TrimPrefix(dnVal, DynamicDataPrefix)
- return dP.FieldAsInterface(strings.Split(dnVal, NestingSep))
- }
- return StringToInterface(dnVal), nil
-}
-
-// DPDynamicString returns the string value of the field if the path is dynamic
-func DPDynamicString(dnVal string, dP DataProvider) (string, error) {
- if strings.HasPrefix(dnVal, DynamicDataPrefix) {
- dnVal = strings.TrimPrefix(dnVal, DynamicDataPrefix)
- return dP.FieldAsString(strings.Split(dnVal, NestingSep))
- }
- return dnVal, nil
-}
-
-// NMType the type used for navigable Map
-type NMType byte
-
-// NMInterface the basic interface
-type NMInterface interface {
- String() string
- Interface() any
- Field(path PathItems) (val NMInterface, err error)
- Set(path PathItems, val NMInterface) (addedNew bool, err error)
- Remove(path PathItems) (err error)
- Type() NMType
- Empty() bool
- Len() int
-}
-
-// navMap subset of function for NM interface
-type navMap interface {
- Field(path PathItems) (val NMInterface, err error)
- Set(fullpath *FullPath, val NMInterface) (addedNew bool, err error)
-}
-
-// AppendNavMapVal appends value to the map
-func AppendNavMapVal(nm navMap, fldPath *FullPath, val NMInterface) (err error) {
- var prevItm NMInterface
- var indx int
- if prevItm, err = nm.Field(fldPath.PathItems); err != nil {
- if err != ErrNotFound {
- return
- }
- } else {
- indx = prevItm.Len()
- }
- fldPath.PathItems[len(fldPath.PathItems)-1].Index = &indx
- _, err = nm.Set(fldPath, val)
- return
-}
-
-// ComposeNavMapVal compose adds value to prevision item
-func ComposeNavMapVal(nm navMap, fldPath *FullPath, val NMInterface) (err error) {
- var prevItmSlice NMInterface
- var indx int
- if prevItmSlice, err = nm.Field(fldPath.PathItems); err != nil {
- if err != ErrNotFound {
- return
- }
- } else {
- indx = prevItmSlice.Len() - 1
- var prevItm NMInterface
- if prevItm, err = prevItmSlice.Field(PathItems{{Index: &indx}}); err != nil {
- if err != ErrNotFound {
- return
- }
- } else if _, err = val.Set(nil, NewNMData(IfaceAsString(prevItm.Interface())+IfaceAsString(val.Interface()))); err != nil {
- return
- }
- }
- fldPath.PathItems[len(fldPath.PathItems)-1].Index = &indx
- _, err = nm.Set(fldPath, val)
- return
-}
-
-
-
/*
-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 utils
-
-import (
- "fmt"
- "net"
- "reflect"
- "sort"
- "strconv"
- "strings"
- "time"
-)
-
-// Defines years days series
-type Years []int
-
-func (ys Years) Sort() {
- sort.Sort(ys)
-}
-
-func (ys Years) Len() int {
- return len(ys)
-}
-
-func (ys Years) Swap(i, j int) {
- ys[i], ys[j] = ys[j], ys[i]
-}
-
-func (ys Years) Less(j, i int) bool {
- return ys[j] < ys[i]
-}
-
-// Return true if the specified date is inside the series
-func (ys Years) Contains(year int) (result bool) {
- result = false
- for _, yss := range ys {
- if yss == year {
- result = true
- break
- }
- }
- return
-}
-
-// Parse Years elements from string separated by sep.
-func (ys *Years) Parse(input, sep string) {
- switch input {
- case META_ANY, EmptyString:
- *ys = []int{}
- default:
- elements := strings.Split(input, sep)
- for _, yss := range elements {
- if year, err := strconv.Atoi(yss); err == nil {
- *ys = append(*ys, year)
- }
- }
- }
-}
-
-func (ys Years) Serialize(sep string) string {
- if len(ys) == 0 {
- return META_ANY
- }
- var yStr string
- for idx, yr := range ys {
- if idx != 0 {
- yStr = fmt.Sprintf("%s%s%d", yStr, sep, yr)
- } else {
- yStr = strconv.Itoa(yr)
- }
- }
- return yStr
-}
-
-// Equals implies that Years are already sorted
-func (ys Years) Equals(oYS Years) bool {
- if len(ys) != len(oYS) {
- return false
- }
- for i := range ys {
- if ys[i] != oYS[i] {
- return false
- }
- }
- return true
-}
-
-// Defines months series
-type Months []time.Month
-
-func (m Months) Sort() {
- sort.Sort(m)
-}
-
-func (m Months) Len() int {
- return len(m)
-}
-
-func (m Months) Swap(i, j int) {
- m[i], m[j] = m[j], m[i]
-}
-
-func (m Months) Less(j, i int) bool {
- return m[j] < m[i]
-}
-
-// Return true if the specified date is inside the series
-func (m Months) Contains(month time.Month) (result bool) {
- for _, ms := range m {
- if ms == month {
- result = true
- break
- }
- }
- return
-}
-
-// Loades Month elemnents from a string separated by sep.
-func (m *Months) Parse(input, sep string) {
- switch input {
- case META_ANY, EmptyString: // Apier cannot receive empty string, hence using meta-tag
- *m = []time.Month{}
- default:
- elements := strings.Split(input, sep)
- for _, ms := range elements {
- if month, err := strconv.Atoi(ms); err == nil {
- *m = append(*m, time.Month(month))
- }
- }
- }
-}
-
-// Dumps the months in a serialized string, similar to the one parsed
-func (m Months) Serialize(sep string) string {
- if len(m) == 0 {
- return META_ANY
- }
- var mStr string
- for idx, mt := range m {
- if idx != 0 {
- mStr = fmt.Sprintf("%s%s%d", mStr, sep, mt)
- } else {
- mStr = strconv.Itoa(int(mt))
- }
- }
- return mStr
-}
-
-func (m Months) IsComplete() bool {
- allMonths := Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}
- m.Sort()
- return reflect.DeepEqual(m, allMonths)
-}
-
-// Equals implies that Months are already sorted
-func (m Months) Equals(oM Months) bool {
- if len(m) != len(oM) {
- return false
- }
- for i := range m {
- if m[i] != oM[i] {
- return false
- }
- }
- return true
-}
-
-// Defines month days series
-type MonthDays []int
-
-func (md MonthDays) Sort() {
- sort.Sort(md)
-}
-
-func (md MonthDays) Len() int {
- return len(md)
-}
-
-func (md MonthDays) Swap(i, j int) {
- md[i], md[j] = md[j], md[i]
-}
-
-func (md MonthDays) Less(j, i int) bool {
- return md[j] < md[i]
-}
-
-// Return true if the specified date is inside the series
-func (md MonthDays) Contains(monthDay int) (result bool) {
- result = false
- for _, mds := range md {
- if mds == monthDay {
- result = true
- break
- }
- }
- return
-}
-
-// Parse MonthDay elements from string separated by sep.
-func (md *MonthDays) Parse(input, sep string) {
- switch input {
- case META_ANY, EmptyString:
- *md = []int{}
- default:
- elements := strings.Split(input, sep)
- for _, mds := range elements {
- if day, err := strconv.Atoi(mds); err == nil {
- *md = append(*md, day)
- }
- }
- }
-}
-
-// Dumps the month days in a serialized string, similar to the one parsed
-func (md MonthDays) Serialize(sep string) string {
- if len(md) == 0 {
- return META_ANY
- }
- var mdsStr string
- for idx, mDay := range md {
- if idx != 0 {
- mdsStr = fmt.Sprintf("%s%s%d", mdsStr, sep, mDay)
- } else {
- mdsStr = strconv.Itoa(mDay)
- }
- }
- return mdsStr
-}
-
-// Equals implies that MonthDays are already sorted
-func (md MonthDays) Equals(oMD MonthDays) bool {
- if len(md) != len(oMD) {
- return false
- }
- for i := range md {
- if md[i] != oMD[i] {
- return false
- }
- }
- return true
-}
-
-// Defines week days series
-type WeekDays []time.Weekday
-
-func (wd WeekDays) Sort() {
- sort.Sort(wd)
-}
-
-func (wd WeekDays) Len() int {
- return len(wd)
-}
-
-func (wd WeekDays) Swap(i, j int) {
- wd[i], wd[j] = wd[j], wd[i]
-}
-
-func (wd WeekDays) Less(j, i int) bool {
- return wd[j] < wd[i]
-}
-
-// Return true if the specified date is inside the series
-func (wd WeekDays) Contains(weekDay time.Weekday) (result bool) {
- result = false
- for _, wds := range wd {
- if wds == weekDay {
- result = true
- break
- }
- }
- return
-}
-
-func (wd *WeekDays) Parse(input, sep string) {
- switch input {
- case META_ANY, EmptyString:
- *wd = []time.Weekday{}
- default:
- elements := strings.Split(input, sep)
- for _, wds := range elements {
- if day, err := strconv.Atoi(wds); err == nil {
- *wd = append(*wd, time.Weekday(day%7)) // %7 for sunday = 7 normalization
- }
- }
- }
-}
-
-// Dumps the week days in a serialized string, similar to the one parsed
-func (wd WeekDays) Serialize(sep string) string {
- if len(wd) == 0 {
- return META_ANY
- }
- var wdStr string
- for idx, d := range wd {
- if idx != 0 {
- wdStr = fmt.Sprintf("%s%s%d", wdStr, sep, d)
- } else {
- wdStr = strconv.Itoa(int(d))
- }
- }
- return wdStr
-}
-
-// Equals implies that WeekDays are already sorted
-func (wd WeekDays) Equals(oWD WeekDays) bool {
- if len(wd) != len(oWD) {
- return false
- }
- for i := range wd {
- if wd[i] != oWD[i] {
- return false
- }
- }
- return true
-}
-
-func DaysInMonth(year int, month time.Month) float64 {
- return float64(time.Date(year, month, 1, 0, 0, 0, 0, time.UTC).AddDate(0, 1, -1).Day())
-}
-
-func DaysInYear(year int) float64 {
- first := time.Date(year, 1, 1, 0, 0, 0, 0, time.UTC)
- last := first.AddDate(1, 0, 0)
- return float64(last.Sub(first).Hours() / 24)
-}
-
-func LocalAddr() *NetAddr {
- return &NetAddr{network: Local, ip: Local}
-}
-
-func NewNetAddr(network, host string) *NetAddr {
- ip, port, err := net.SplitHostPort(host)
- if err != nil {
- Logger.Warning(fmt.Sprintf("failed parsing RemoteAddr: %s, err: %s",
- host, err.Error()))
- }
- p, err := strconv.Atoi(port)
- if err != nil {
- Logger.Warning(fmt.Sprintf("failed converting port : %+v, err: %s",
- port, err.Error()))
- }
- return &NetAddr{network: network, ip: ip, port: p}
-}
-
-type NetAddr struct {
- network string
- ip string
- port int
-}
-
-// Network is part of net.Addr interface
-func (lc *NetAddr) Network() string {
- return lc.network
-}
-
-// String is part of net.Addr interface
-func (lc *NetAddr) String() string {
- return lc.ip
-}
-
-// Port
-func (lc *NetAddr) Port() int {
- return lc.port
-}
-
-// Host
-func (lc *NetAddr) Host() string {
- if lc.ip == Local {
- return Local
- }
- return ConcatenatedKey(lc.ip, strconv.Itoa(lc.port))
-}
-
-
-
/*
-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 utils
-
-import (
- "errors"
- "fmt"
- "net"
- "net/rpc"
- "strings"
-)
-
-var (
- ErrNoMoreData = errors.New("NO_MORE_DATA")
- ErrNotImplemented = errors.New("NOT_IMPLEMENTED")
- ErrNotFound = errors.New("NOT_FOUND")
- ErrTimedOut = errors.New("TIMED_OUT")
- ErrServerError = errors.New("SERVER_ERROR")
- ErrMaxRecursionDepth = errors.New("MAX_RECURSION_DEPTH")
- ErrMandatoryIeMissing = errors.New("MANDATORY_IE_MISSING")
- ErrExists = errors.New("EXISTS")
- ErrBrokenReference = errors.New("BROKEN_REFERENCE")
- ErrParserError = errors.New("PARSER_ERROR")
- ErrInvalidPath = errors.New("INVALID_PATH")
- ErrInvalidKey = errors.New("INVALID_KEY")
- ErrUnauthorizedDestination = errors.New("UNAUTHORIZED_DESTINATION")
- ErrRatingPlanNotFound = errors.New("RATING_PLAN_NOT_FOUND")
- ErrAccountNotFound = errors.New("ACCOUNT_NOT_FOUND")
- ErrAccountDisabled = errors.New("ACCOUNT_DISABLED")
- ErrInsufficientCredit = errors.New("INSUFFICIENT_CREDIT")
- ErrNotConvertible = errors.New("NOT_CONVERTIBLE")
- ErrResourceUnavailable = errors.New("RESOURCE_UNAVAILABLE")
- ErrResourceUnauthorized = errors.New("RESOURCE_UNAUTHORIZED")
- ErrNoActiveSession = errors.New("NO_ACTIVE_SESSION")
- ErrPartiallyExecuted = errors.New("PARTIALLY_EXECUTED")
- ErrMaxUsageExceeded = errors.New("MAX_USAGE_EXCEEDED")
- ErrFilterNotPassingNoCaps = errors.New("filter not passing")
- ErrNotConvertibleNoCaps = errors.New("not convertible")
- ErrMandatoryIeMissingNoCaps = errors.New("mandatory information missing")
- ErrUnauthorizedApi = errors.New("UNAUTHORIZED_API")
- ErrUnknownApiKey = errors.New("UNKNOWN_API_KEY")
- ErrReqUnsynchronized = errors.New("REQ_UNSYNCHRONIZED")
- ErrUnsupporteServiceMethod = errors.New("UNSUPPORTED_SERVICE_METHOD")
- ErrDisconnected = errors.New("DISCONNECTED")
- ErrReplyTimeout = errors.New("REPLY_TIMEOUT")
- ErrSessionNotFound = errors.New("SESSION_NOT_FOUND")
- ErrJsonIncompleteComment = errors.New("JSON_INCOMPLETE_COMMENT")
- ErrNotEnoughParameters = errors.New("NotEnoughParameters")
- ErrNotConnected = errors.New("NOT_CONNECTED")
- RalsErrorPrfx = "RALS_ERROR"
- DispatcherErrorPrefix = "DISPATCHER_ERROR"
- ErrUnsupportedFormat = errors.New("UNSUPPORTED_FORMAT")
- ErrNoDatabaseConn = errors.New("NO_DATA_BASE_CONNECTION")
- ErrMaxIncrementsExceeded = errors.New("MAX_INCREMENTS_EXCEEDED")
- ErrIndexOutOfBounds = errors.New("INDEX_OUT_OF_BOUNDS")
- ErrWrongPath = errors.New("WRONG_PATH")
- ErrServiceAlreadyRunning = fmt.Errorf("service already running")
-
- ErrMap = map[string]error{
- ErrNoMoreData.Error(): ErrNoMoreData,
- ErrNotImplemented.Error(): ErrNotImplemented,
- ErrNotFound.Error(): ErrNotFound,
- ErrTimedOut.Error(): ErrTimedOut,
- ErrServerError.Error(): ErrServerError,
- ErrMaxRecursionDepth.Error(): ErrMaxRecursionDepth,
- ErrExists.Error(): ErrExists,
- ErrBrokenReference.Error(): ErrBrokenReference,
- ErrParserError.Error(): ErrParserError,
- ErrInvalidPath.Error(): ErrInvalidPath,
- ErrInvalidKey.Error(): ErrInvalidKey,
- ErrUnauthorizedDestination.Error(): ErrUnauthorizedDestination,
- ErrRatingPlanNotFound.Error(): ErrRatingPlanNotFound,
- ErrInsufficientCredit.Error(): ErrInsufficientCredit,
- ErrNotConvertible.Error(): ErrNotConvertible,
- ErrResourceUnavailable.Error(): ErrResourceUnavailable,
- ErrResourceUnauthorized.Error(): ErrResourceUnauthorized,
- ErrNoActiveSession.Error(): ErrNoActiveSession,
- ErrPartiallyExecuted.Error(): ErrPartiallyExecuted,
- ErrMaxUsageExceeded.Error(): ErrMaxUsageExceeded,
- ErrFilterNotPassingNoCaps.Error(): ErrFilterNotPassingNoCaps,
- ErrNotConvertibleNoCaps.Error(): ErrNotConvertibleNoCaps,
- ErrUnauthorizedApi.Error(): ErrUnauthorizedApi,
- ErrUnknownApiKey.Error(): ErrUnknownApiKey,
- ErrReqUnsynchronized.Error(): ErrReqUnsynchronized,
- ErrUnsupporteServiceMethod.Error(): ErrUnsupporteServiceMethod,
- ErrDisconnected.Error(): ErrDisconnected,
- ErrReplyTimeout.Error(): ErrReplyTimeout,
- ErrSessionNotFound.Error(): ErrSessionNotFound,
- ErrJsonIncompleteComment.Error(): ErrJsonIncompleteComment,
- ErrNotEnoughParameters.Error(): ErrNotEnoughParameters,
- ErrUnsupportedFormat.Error(): ErrUnsupportedFormat,
- ErrNoDatabaseConn.Error(): ErrNoDatabaseConn,
- ErrMaxIncrementsExceeded.Error(): ErrMaxIncrementsExceeded,
- ErrIndexOutOfBounds.Error(): ErrIndexOutOfBounds,
- ErrWrongPath.Error(): ErrWrongPath,
- }
-)
-
-// NewCGRError initialises a new CGRError
-func NewCGRError(context, apiErr, shortErr, longErr string) *CGRError {
- return &CGRError{context: context, apiError: apiErr,
- shortError: shortErr, longError: longErr, errorMessage: shortErr}
-}
-
-// CGRError is a context based error
-// returns always errorMessage but this can be switched based on methods called on it
-type CGRError struct {
- context string
- apiError string
- shortError string
- longError string
- errorMessage string
-}
-
-func (err *CGRError) Context() string {
- return err.context
-}
-
-func (err *CGRError) Error() string {
- return err.errorMessage
-}
-
-func (err *CGRError) ActivateAPIError() {
- err.errorMessage = err.apiError
-}
-
-func (err *CGRError) ActivateShortError() {
- err.errorMessage = err.shortError
-}
-
-func (err *CGRError) ActivateLongError() {
- err.errorMessage = err.longError
-}
-
-func NewErrMandatoryIeMissing(fields ...string) error {
- return fmt.Errorf("MANDATORY_IE_MISSING: %v", fields)
-}
-
-func NewErrServerError(err error) error {
- return fmt.Errorf("SERVER_ERROR: %s", err)
-}
-
-func NewErrServiceNotOperational(serv string) error {
- return fmt.Errorf("SERVICE_NOT_OPERATIONAL: %s", serv)
-}
-
-func NewErrNotConnected(serv string) error {
- return fmt.Errorf("NOT_CONNECTED: %s", serv)
-}
-
-func NewErrRALs(err error) error {
- return fmt.Errorf("%s:%s", RalsErrorPrfx, err)
-}
-
-func NewErrResourceS(err error) error {
- return fmt.Errorf("RESOURCES_ERROR:%s", err)
-}
-
-func NewErrSupplierS(err error) error {
- return fmt.Errorf("SUPPLIERS_ERROR:%s", err)
-}
-
-func NewErrAttributeS(err error) error {
- return fmt.Errorf("ATTRIBUTES_ERROR:%s", err)
-}
-
-func NewErrChargerS(err error) error {
- return fmt.Errorf("CHARGERS_ERROR:%s", err)
-}
-
-func NewErrDispatcherS(err error) error {
- return fmt.Errorf("%s:%s", DispatcherErrorPrefix, err.Error())
-}
-
-// Centralized returns for APIs
-func APIErrorHandler(errIn error) (err error) {
- cgrErr, ok := errIn.(*CGRError)
- if !ok {
- err = errIn
- if err != ErrNotFound {
- err = NewErrServerError(err)
- }
- return
- }
- cgrErr.ActivateAPIError()
- return cgrErr
-}
-
-func NewErrStringCast(valIface any) error {
- return fmt.Errorf("cannot cast value: %v to string", valIface)
-}
-
-func NewErrFldStringCast(fldName string, valIface any) error {
- return fmt.Errorf("cannot cast field: %s with value: %v to string", fldName, valIface)
-}
-
-func ErrHasPrefix(err error, prfx string) (has bool) {
- if err == nil {
- return
- }
- return strings.HasPrefix(err.Error(), prfx)
-}
-
-func ErrPrefix(err error, reason string) error {
- return fmt.Errorf("%s:%s", err.Error(), reason)
-}
-
-func ErrPrefixNotFound(reason string) error {
- return ErrPrefix(ErrNotFound, reason)
-}
-
-func ErrPrefixNotErrNotImplemented(reason string) error {
- return ErrPrefix(ErrNotImplemented, reason)
-}
-
-func ErrEnvNotFound(key string) error {
- return ErrPrefix(ErrNotFound, "ENV_VAR:"+key)
-}
-
-// IsNetworkError will decide if an error is network generated or RPC one
-// used by Dispatcher to figure out whether it should try another connection
-func IsNetworkError(err error) bool {
- if err == nil {
- return false
- }
- if _, isNetError := err.(*net.OpError); isNetError { // connection reset
- return true
- }
- if _, isDNSError := err.(*net.DNSError); isDNSError {
- return true
- }
- return err.Error() == rpc.ErrShutdown.Error() ||
- err.Error() == ErrReqUnsynchronized.Error() ||
- err.Error() == ErrDisconnected.Error() ||
- err.Error() == ErrReplyTimeout.Error() ||
- err.Error() == ErrSessionNotFound.Error() ||
- strings.HasPrefix(err.Error(), "rpc: can't find service")
-}
-
-func ErrPathNotReachable(path string) error {
- return fmt.Errorf("path:%+q is not reachable", path)
-}
-
-func ErrNotConvertibleTF(from, to string) error {
- return fmt.Errorf("%s : from: %s to:%s", ErrNotConvertibleNoCaps.Error(), from, to)
-}
-
-
-
/*
-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 utils
-
-import (
- "encoding/json"
- "errors"
- "io"
- "net/rpc"
- "strings"
- "sync"
-)
-
-var errMissingParams = errors.New("jsonrpc: request body missing params")
-
-type MethodParameters struct {
- Method string
- Parameters any
-}
-
-type jsonServerCodec struct {
- dec *json.Decoder // for reading JSON values
- enc *json.Encoder // for writing JSON values
- c io.Closer
-
- // temporary work space
- req serverRequest
-
- // JSON-RPC clients can use arbitrary json values as request IDs.
- // Package rpc expects uint64 request IDs.
- // We assign uint64 sequence numbers to incoming requests
- // but save the original request ID in the pending map.
- // When rpc responds, we use the sequence number in
- // the response to find the original request ID.
- mutex sync.Mutex // protects seq, pending
- seq uint64
- pending map[uint64]*json.RawMessage
-}
-
-// NewCustomJSONServerCodec is used only when DispatcherS is active to handle APIer methods generically
-func NewCustomJSONServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
- return &jsonServerCodec{
- dec: json.NewDecoder(conn),
- enc: json.NewEncoder(conn),
- c: conn,
- pending: make(map[uint64]*json.RawMessage),
- }
-}
-
-type serverRequest struct {
- Method string `json:"method"`
- Params *json.RawMessage `json:"params"`
- Id *json.RawMessage `json:"id"`
- isApier bool
-}
-
-func (r *serverRequest) reset() {
- r.Method = ""
- r.Params = nil
- r.Id = nil
-}
-
-type serverResponse struct {
- Id *json.RawMessage `json:"id"`
- Result any `json:"result"`
- Error any `json:"error"`
-}
-
-func (c *jsonServerCodec) ReadRequestHeader(r *rpc.Request) error {
- c.req.reset()
- if err := c.dec.Decode(&c.req); err != nil {
- return err
- }
- // in case we get a request with APIerSv1 or APIerSv2 we redirect
- // to Dispatcher to send it according to ArgDispatcher
- if c.req.isApier = strings.HasPrefix(c.req.Method, ApierV); c.req.isApier {
- r.ServiceMethod = DispatcherSv1Apier
- } else {
- r.ServiceMethod = c.req.Method
- }
-
- // JSON request id can be any JSON value;
- // RPC package expects uint64. Translate to
- // internal uint64 and save JSON on the side.
- c.mutex.Lock()
- c.seq++
- c.pending[c.seq] = c.req.Id
- c.req.Id = nil
- r.Seq = c.seq
- c.mutex.Unlock()
-
- return nil
-}
-
-func (c *jsonServerCodec) ReadRequestBody(x any) error {
- if x == nil {
- return nil
- }
- if c.req.Params == nil {
- return errMissingParams
- }
- // following example from ReadRequestHeader in case we get APIerSv1
- // or APIerSv2 we compose the parameters
- if c.req.isApier {
- cx := x.(*MethodParameters)
- cx.Method = c.req.Method
- var params [1]any
- params[0] = &cx.Parameters
- return json.Unmarshal(*c.req.Params, ¶ms)
- }
- // JSON params is array value.
- // RPC params is struct.
- // Unmarshal into array containing struct for now.
- // Should think about making RPC more general.
- var params [1]any
- params[0] = x
- return json.Unmarshal(*c.req.Params, ¶ms)
-
-}
-
-var null = json.RawMessage([]byte("null"))
-
-func (c *jsonServerCodec) WriteResponse(r *rpc.Response, x any) error {
- c.mutex.Lock()
- b, ok := c.pending[r.Seq]
- if !ok {
- c.mutex.Unlock()
- return errors.New("invalid sequence number in response")
- }
- delete(c.pending, r.Seq)
- c.mutex.Unlock()
-
- if b == nil {
- // Invalid request so no id. Use JSON null.
- b = &null
- }
- resp := serverResponse{Id: b}
- if r.Error == "" {
- resp.Result = x
- } else {
- resp.Error = r.Error
- }
- return c.enc.Encode(resp)
-}
-
-func (c *jsonServerCodec) Close() error {
- return c.c.Close()
-}
-
-
-
/*
-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 utils
-
-import (
- "fmt"
- "log"
- "log/syslog"
- "reflect"
- "runtime"
-)
-
-var Logger LoggerInterface
-var nodeID string
-
-func init() {
- if Logger == nil || reflect.ValueOf(Logger).IsNil() {
- err := Newlogger(MetaSysLog, nodeID)
- if err != nil {
- Logger.Err(fmt.Sprintf("Could not connect to syslog: %v", err))
- }
- }
-}
-
-// functie Newlogger (logger type)
-func Newlogger(loggertype, id string) (err error) {
- Logger = new(StdLogger)
- nodeID = id
- var l *syslog.Writer
- if loggertype == MetaSysLog {
- if l, err = syslog.New(syslog.LOG_INFO|syslog.LOG_DAEMON, fmt.Sprintf("CGRateS <%s> ", nodeID)); err != nil {
- return err
- } else {
- Logger.SetSyslog(l)
- }
- return nil
- } else if loggertype != MetaStdLog {
- return fmt.Errorf("unsuported logger: <%s>", loggertype)
- }
- return nil
-}
-
-type LoggerInterface interface {
- SetSyslog(log *syslog.Writer)
- SetLogLevel(level int)
- GetSyslog() *syslog.Writer
- Close() error
- Emerg(m string) error
- Alert(m string) error
- Crit(m string) error
- Err(m string) error
- Warning(m string) error
- Notice(m string) error
- Info(m string) error
- Debug(m string) error
- Write(p []byte) (n int, err error)
-}
-
-// log severities following rfc3164
-const (
- LOGLEVEL_EMERGENCY = iota
- LOGLEVEL_ALERT
- LOGLEVEL_CRITICAL
- LOGLEVEL_ERROR
- LOGLEVEL_WARNING
- LOGLEVEL_NOTICE
- LOGLEVEL_INFO
- LOGLEVEL_DEBUG
-)
-
-// Logs to standard output
-type StdLogger struct {
- logLevel int
- syslog *syslog.Writer
-}
-
-func (sl *StdLogger) Close() (err error) {
- if sl.syslog != nil {
- sl.Close()
- }
- return
-}
-func (sl *StdLogger) Write(p []byte) (n int, err error) {
- s := string(p[:])
- fmt.Print(s)
- return 1, nil
-}
-
-// SetSyslog sets the logger for the server
-func (sl *StdLogger) SetSyslog(l *syslog.Writer) {
- sl.syslog = l
-}
-
-// GetSyslog returns the logger for the server
-func (sl *StdLogger) GetSyslog() *syslog.Writer {
- return sl.syslog
-}
-
-// SetLogLevel changes the log level
-func (sl *StdLogger) SetLogLevel(level int) {
- sl.logLevel = level
-}
-
-// Alert logs to syslog with alert level
-func (sl *StdLogger) Alert(m string) (err error) {
- if sl.logLevel < LOGLEVEL_ALERT {
- return
- }
- if sl.syslog != nil {
- sl.syslog.Alert(m)
- } else {
- log.Print("CGRateS <" + nodeID + "> [ALERT] " + m)
- }
- return
-}
-
-// Crit logs to syslog with critical level
-func (sl *StdLogger) Crit(m string) (err error) {
- if sl.logLevel < LOGLEVEL_CRITICAL {
- return
- }
- if sl.syslog != nil {
- sl.syslog.Crit(m)
- } else {
- log.Print("CGRateS <" + nodeID + "> [CRITICAL] " + m)
- }
- return
-}
-
-// Debug logs to syslog with debug level
-func (sl *StdLogger) Debug(m string) (err error) {
- if sl.logLevel < LOGLEVEL_DEBUG {
- return
- }
- if sl.syslog != nil {
- sl.syslog.Debug(m)
- } else {
- log.Print("CGRateS <" + nodeID + "> [DEBUG] " + m)
- }
- return
-}
-
-// Emerg logs to syslog with emergency level
-func (sl *StdLogger) Emerg(m string) (err error) {
- if sl.logLevel < LOGLEVEL_EMERGENCY {
- return
- }
- if sl.syslog != nil {
- sl.syslog.Emerg(m)
- } else {
- log.Print("CGRateS <" + nodeID + "> [EMERGENCY] " + m)
- }
- return
-}
-
-// Err logs to syslog with error level
-func (sl *StdLogger) Err(m string) (err error) {
- if sl.logLevel < LOGLEVEL_ERROR {
- return
- }
- if sl.syslog != nil {
- sl.syslog.Err(m)
- } else {
- log.Print("CGRateS <" + nodeID + "> [ERROR] " + m)
- }
- return
-}
-
-// Info logs to syslog with info level
-func (sl *StdLogger) Info(m string) (err error) {
- if sl.logLevel < LOGLEVEL_INFO {
- return
- }
- if sl.syslog != nil {
- sl.syslog.Info(m)
- } else {
- log.Print("CGRateS <" + nodeID + "> [INFO] " + m)
- }
- return
-}
-
-// Notice logs to syslog with notice level
-func (sl *StdLogger) Notice(m string) (err error) {
- if sl.logLevel < LOGLEVEL_NOTICE {
- return
- }
- if sl.syslog != nil {
- sl.syslog.Notice(m)
- } else {
- log.Print("CGRateS <" + nodeID + "> [NOTICE] " + m)
- }
- return
-}
-
-// Warning logs to syslog with warning level
-func (sl *StdLogger) Warning(m string) (err error) {
- if sl.logLevel < LOGLEVEL_WARNING {
- return
- }
-
- if sl.syslog != nil {
- sl.syslog.Warning(m)
- } else {
- log.Print("CGRateS <" + nodeID + "> [WARNING] " + m)
- }
- return
-}
-
-// LogStack logs to syslog the stack trace using debug level
-func LogStack() {
- buf := make([]byte, 300)
- runtime.Stack(buf, false)
- Logger.Debug(string(buf))
-}
-
-
-
/*
-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 utils
-
-import (
- "reflect"
- "strconv"
- "strings"
-)
-
-// Converts map[string]string into map[string]any
-func ConvertMapValStrIf(inMap map[string]string) map[string]any {
- outMap := make(map[string]any)
- for field, val := range inMap {
- outMap[field] = val
- }
- return outMap
-}
-
-// Mirrors key/val
-func MirrorMap(mapIn map[string]string) map[string]string {
- mapOut := make(map[string]string, len(mapIn))
- for key, val := range mapIn {
- mapOut[val] = key
- }
- return mapOut
-}
-
-// Returns mising keys in a map
-func MissingMapKeys(inMap map[string]string, requiredKeys []string) []string {
- missingKeys := []string{}
- for _, reqKey := range requiredKeys {
- if val, hasKey := inMap[reqKey]; !hasKey || val == EmptyString {
- missingKeys = append(missingKeys, reqKey)
- }
- }
- return missingKeys
-}
-
-// Return map keys
-func MapKeys(m map[string]string) []string {
- n := make([]string, len(m))
- i := 0
- for k := range m {
- n[i] = k
- i++
- }
- return n
-}
-
-type StringMap map[string]bool
-
-func NewStringMap(s ...string) StringMap {
- result := make(StringMap)
- for _, v := range s {
- v = strings.TrimSpace(v)
- if v != EmptyString {
- if strings.HasPrefix(v, NegativePrefix) {
- result[v[1:]] = false
- } else {
- result[v] = true
- }
- }
- }
- return result
-}
-
-func ParseStringMap(s string) StringMap {
- if s == ZERO {
- return make(StringMap)
- }
- return StringMapFromSlice(strings.Split(s, INFIELD_SEP))
-}
-
-func (sm StringMap) Equal(om StringMap) bool {
- if sm == nil && om != nil {
- return false
- }
- if len(sm) != len(om) {
- return false
- }
- for key := range sm {
- if !om[key] {
- return false
- }
- }
- return true
-}
-
-func (sm StringMap) Includes(om StringMap) bool {
- if len(sm) < len(om) {
- return false
- }
- for key := range om {
- if !sm[key] {
- return false
- }
- }
- return true
-}
-
-func (sm StringMap) IsEmpty() bool {
- return len(sm) == 0 || sm[ANY]
-}
-
-func StringMapFromSlice(s []string) StringMap {
- result := make(StringMap, len(s))
- for _, v := range s {
- v = strings.TrimSpace(v)
- if v != EmptyString {
- if strings.HasPrefix(v, NegativePrefix) {
- result[v[1:]] = false
- } else {
- result[v] = true
- }
- }
- }
- return result
-}
-
-func (sm StringMap) Copy(o StringMap) {
- for k, v := range o {
- sm[k] = v
- }
-}
-
-func (sm StringMap) Clone() StringMap {
- result := make(StringMap, len(sm))
- result.Copy(sm)
- return result
-}
-
-func (sm StringMap) String() string {
- return strings.Join(sm.Slice(), INFIELD_SEP)
-}
-
-func (sm StringMap) GetOne() string {
- for key := range sm {
- return key
- }
- return EmptyString
-}
-
-func (sm StringMap) Join(mps ...StringMap) {
- for _, mp := range mps {
- for k, v := range mp {
- sm[k] = v
- }
- }
-}
-
-func (sm StringMap) HasKey(key string) (has bool) {
- _, has = sm[key]
- return
-}
-
-func (sm StringMap) Slice() []string {
- result := make([]string, len(sm))
- i := 0
- for k := range sm {
- result[i] = k
- i++
- }
- return result
-}
-
-// Used to merge multiple maps (eg: output of struct having ExtraFields)
-func MergeMapsStringIface(mps ...map[string]any) (outMp map[string]any) {
- outMp = make(map[string]any)
- for i, mp := range mps {
- if i == 0 {
- outMp = mp
- continue
- }
- for k, v := range mp {
- outMp[k] = v
- }
- }
- return
-}
-
-// FieldMultiplyFactor defines multiply factors for different field values
-// original defined for CDRE component
-type FieldMultiplyFactor map[string]float64
-
-func (fmp FieldMultiplyFactor) Clone() (cln FieldMultiplyFactor) {
- cln = make(FieldMultiplyFactor, len(fmp))
- for k, v := range fmp {
- cln[k] = v
- }
- return
-}
-
-func MapStringToInt64(in map[string]string) (out map[string]int64, err error) {
- mapout := make(map[string]int64, len(in))
- for key, val := range in {
- x, err := strconv.Atoi(val)
- if err != nil {
- return nil, err
- }
- mapout[key] = int64(x)
- }
- return mapout, nil
-}
-
-// FlagsWithParamsFromSlice construct a FlagsWithParams from the given slice
-func FlagsWithParamsFromSlice(s []string) (FlagsWithParams, error) {
- result := make(FlagsWithParams, len(s))
- for _, v := range s {
- subsystemWithIDs := strings.Split(v, InInFieldSep)
- result[subsystemWithIDs[0]] = []string{}
- if len(subsystemWithIDs) == 2 {
- result[subsystemWithIDs[0]] = strings.Split(subsystemWithIDs[1], INFIELD_SEP)
- } else if len(subsystemWithIDs) > 2 {
- return nil, ErrUnsupportedFormat
- }
- }
- return result, nil
-}
-
-// FlagsWithParams should store a list of profiles for each subsystem
-type FlagsWithParams map[string][]string
-
-// HasKey returns if the key was mentioned in flags
-func (fWp FlagsWithParams) HasKey(key string) (has bool) {
- _, has = fWp[key]
- return
-}
-
-// ParamsSlice returns the list of profiles for the subsystem
-func (fWp FlagsWithParams) ParamsSlice(subs string) (ps []string) {
- if psIfc, has := fWp[subs]; has {
- ps = psIfc
- }
- return
-}
-
-// ParamValue returns the value of the flag
-func (fWp FlagsWithParams) ParamValue(subs string) (ps string) {
- for _, ps = range fWp[subs] {
- return
- }
- return
-}
-
-// SliceFlags converts from FlagsWithParams back to []string
-func (fWp FlagsWithParams) SliceFlags() (sls []string) {
- for key := range fWp {
- if prmSlice := fWp.ParamsSlice(key); !reflect.DeepEqual(prmSlice, []string{}) {
- sls = append(sls, ConcatenatedKey(key, strings.Join(prmSlice, INFIELD_SEP)))
- } else {
- sls = append(sls, key)
- }
- }
- return
-}
-
-// GetBool returns the flag as boolean
-func (fWp FlagsWithParams) GetBool(key string) (b bool) {
- var v []string
- if v, b = fWp[key]; !b {
- return // not present means false
- }
- if len(v) == 0 {
- return true // empty slice
- }
- return v[0] == "true" // check only the first element
-}
-
-
-
/*
-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 utils
-
-import (
- "errors"
- "fmt"
- "net"
- "reflect"
- "strings"
- "time"
-)
-
-// dataStorage is the DataProvider that can be updated
-type dataStorage interface {
- DataProvider
-
- Set(fldPath []string, val any) error
- Remove(fldPath []string) error
- GetKeys(nesteed bool) []string
-}
-
-// MapStorage is the basic dataStorage
-type MapStorage map[string]any
-
-// String returns the map as json string
-func (ms MapStorage) String() string { return ToJSON(ms) }
-
-// FieldAsInterface returns the value from the path
-func (ms MapStorage) FieldAsInterface(fldPath []string) (val any, err error) {
- if len(fldPath) == 0 {
- err = errors.New("empty field path")
- return
-
- }
- opath, indx := GetPathIndex(fldPath[0])
- var has bool
- if val, has = ms[opath]; !has {
- err = ErrNotFound
- return
- }
- if len(fldPath) == 1 {
- if indx == nil {
- return
- }
- switch rv := val.(type) {
- case []string:
- if len(rv) <= *indx {
- return nil, ErrNotFound
- }
- val = rv[*indx]
- return
- case []any:
- if len(rv) <= *indx {
- return nil, ErrNotFound
- }
- val = rv[*indx]
- return
- default:
- }
- // only if all above fails use reflect:
- vr := reflect.ValueOf(val)
- if vr.Kind() == reflect.Ptr {
- vr = vr.Elem()
- }
- if vr.Kind() != reflect.Slice && vr.Kind() != reflect.Array {
- return nil, ErrNotFound
-
- }
- if *indx >= vr.Len() {
- return nil, ErrNotFound
- }
- return vr.Index(*indx).Interface(), nil
-
- }
- if indx == nil {
- switch dp := ms[fldPath[0]].(type) {
- case DataProvider:
- return dp.FieldAsInterface(fldPath[1:])
- case map[string]any:
- return MapStorage(dp).FieldAsInterface(fldPath[1:])
- default:
- err = ErrWrongPath
-
- return
- }
- }
- switch dp := ms[opath].(type) {
- case []DataProvider:
- if len(dp) <= *indx {
- return nil, ErrNotFound
- }
- return dp[*indx].FieldAsInterface(fldPath[1:])
- case []MapStorage:
- if len(dp) <= *indx {
- return nil, ErrNotFound
- }
- return dp[*indx].FieldAsInterface(fldPath[1:])
- case []map[string]any:
- if len(dp) <= *indx {
- return nil, ErrNotFound
-
- }
- return MapStorage(dp[*indx]).FieldAsInterface(fldPath[1:])
- case []any:
- if len(dp) <= *indx {
- return nil, ErrNotFound
- }
- switch ds := dp[*indx].(type) {
- case DataProvider:
- return ds.FieldAsInterface(fldPath[1:])
- case map[string]any:
- return MapStorage(ds).FieldAsInterface(fldPath[1:])
- default:
- }
- default:
-
- }
- err = ErrNotFound // xml compatible
- val = nil
- return
-}
-
-// FieldAsString returns the value from path as string
-func (ms MapStorage) FieldAsString(fldPath []string) (str string, err error) {
- var val any
- if val, err = ms.FieldAsInterface(fldPath); err != nil {
- return
- }
- return IfaceAsString(val), nil
-}
-
-// Set sets the value at the given path
-func (ms MapStorage) Set(fldPath []string, val any) (err error) {
- if len(fldPath) == 0 {
- return ErrWrongPath
- }
- if len(fldPath) == 1 {
- ms[fldPath[0]] = val
-
- return
- }
-
- if _, has := ms[fldPath[0]]; !has {
- nMap := MapStorage{}
- ms[fldPath[0]] = nMap
- return nMap.Set(fldPath[1:], val)
- }
- switch dp := ms[fldPath[0]].(type) {
- case dataStorage:
- return dp.Set(fldPath[1:], val)
- case map[string]any:
- return MapStorage(dp).Set(fldPath[1:], val)
- default:
- return ErrWrongPath
- }
-
-}
-
-// GetKeys returns all the keys from map
-func (ms MapStorage) GetKeys(nesteed bool) (keys []string) {
- if !nesteed {
- keys = make([]string, len(ms))
- i := 0
- for k := range ms {
- keys[i] = k
- i++
-
- }
- return
- }
- for k, v := range ms {
- // keys = append(keys, k)
- switch rv := v.(type) {
- case dataStorage:
- for _, dsKey := range rv.GetKeys(nesteed) {
- keys = append(keys, k+NestingSep+dsKey)
- }
- case map[string]any:
- for _, dsKey := range MapStorage(rv).GetKeys(nesteed) {
- keys = append(keys, k+NestingSep+dsKey)
- }
- case []MapStorage:
- for i, dp := range rv {
- pref := k + fmt.Sprintf("[%v]", i)
- // keys = append(keys, pref)
- for _, dsKey := range dp.GetKeys(nesteed) {
- keys = append(keys, pref+NestingSep+dsKey)
- }
- }
- case []dataStorage:
- for i, dp := range rv {
- pref := k + fmt.Sprintf("[%v]", i)
- // keys = append(keys, pref)
- for _, dsKey := range dp.GetKeys(nesteed) {
- keys = append(keys, pref+NestingSep+dsKey)
- }
- }
- case []map[string]any:
- for i, dp := range rv {
- pref := k + fmt.Sprintf("[%v]", i)
- // keys = append(keys, pref)
- for _, dsKey := range MapStorage(dp).GetKeys(nesteed) {
- keys = append(keys, pref+NestingSep+dsKey)
- }
- }
- case []any:
- for i := range rv {
- keys = append(keys, k+fmt.Sprintf("[%v]", i))
- }
- case []string:
- for i := range rv {
- keys = append(keys, k+fmt.Sprintf("[%v]", i))
- }
- case nil, int, int32, int64, uint32, uint64, bool, float32, float64, []uint8, time.Duration, time.Time, string: //no path
- keys = append(keys, k)
- default:
- // ToDo:should not be called
- keys = append(keys, getPathFromValue(reflect.ValueOf(v), k+NestingSep)...)
- }
-
- }
- return
-
-}
-
-// Remove removes the item at path
-func (ms MapStorage) Remove(fldPath []string) (err error) {
- if len(fldPath) == 0 {
- return ErrWrongPath
- }
- var val any
- var has bool
- if val, has = ms[fldPath[0]]; !has {
- return // ignore (already removed)
- }
- if len(fldPath) == 1 {
- delete(ms, fldPath[0])
-
- return
- }
- switch dp := val.(type) {
- case dataStorage:
- return dp.Remove(fldPath[1:])
- case map[string]any:
- return MapStorage(dp).Remove(fldPath[1:])
- default:
- return ErrWrongPath
-
- }
-
-}
-
-// RemoteHost is part of dataStorage interface
-func (ms MapStorage) RemoteHost() net.Addr {
- return LocalAddr()
-}
-
-// ToDo: remove the following functions
-func getPathFromValue(in reflect.Value, prefix string) (out []string) {
- switch in.Kind() {
- case reflect.Ptr:
- return getPathFromValue(in.Elem(), prefix)
- case reflect.Array, reflect.Slice:
- prefix = strings.TrimSuffix(prefix, NestingSep)
- for i := 0; i < in.Len(); i++ {
- pref := fmt.Sprintf("%s[%v]", prefix, i)
- // out = append(out, pref)
- out = append(out, getPathFromValue(in.Index(i), pref+NestingSep)...)
- }
- case reflect.Map:
- iter := reflect.ValueOf(in).MapRange()
- for iter.Next() {
- pref := prefix + iter.Key().String()
- // out = append(out, pref)
- out = append(out, getPathFromValue(iter.Value(), pref+NestingSep)...)
- }
- case reflect.Struct:
- inType := in.Type()
- for i := 0; i < in.NumField(); i++ {
- pref := prefix + inType.Field(i).Name
- // out = append(out, pref)
- out = append(out, getPathFromValue(in.Field(i), pref+NestingSep)...)
- }
- case reflect.Invalid, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String, reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Interface:
- out = append(out, strings.TrimSuffix(prefix, NestingSep))
- default:
- }
- return
-}
-
-
-
/*
-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 utils
-
-import (
- "net"
-)
-
-// NavigableMap2 is the basic map of NM interface
-type NavigableMap2 map[string]NMInterface
-
-func (nm NavigableMap2) String() (out string) {
- for k, v := range nm {
- out += ",\"" + k + "\":" + v.String()
- }
- if len(out) == 0 {
- return "{}"
- }
- out = out[1:]
- return "{" + out + "}"
-}
-
-// Interface returns itself
-func (nm NavigableMap2) Interface() any {
- return nm
-}
-
-// Field returns the item on the given path
-func (nm NavigableMap2) Field(path PathItems) (val NMInterface, err error) {
- if len(path) == 0 {
- return nil, ErrWrongPath
- }
- el, has := nm[path[0].Field]
- if !has {
- return nil, ErrNotFound
- }
- if len(path) == 1 && path[0].Index == nil {
- return el, nil
- }
- switch el.Type() {
- default:
- return nil, ErrNotFound
- case NMMapType:
- if path[0].Index != nil {
- return nil, ErrNotFound
- }
- return el.Field(path[1:])
- case NMSliceType:
- return el.Field(path)
- }
-}
-
-// Set sets the value for the given path
-func (nm NavigableMap2) Set(path PathItems, val NMInterface) (added bool, err error) {
- if len(path) == 0 {
- return false, ErrWrongPath
- }
- nmItm, has := nm[path[0].Field]
-
- if path[0].Index != nil { // has index, should be a slice which is kinda part of our map, hence separate handling
- if !has {
- nmItm = &NMSlice{}
- if _, err = nmItm.Set(path, val); err != nil {
- return
- }
- nm[path[0].Field] = nmItm
- added = true
- return
- }
- if nmItm.Type() != NMSliceType {
- return false, ErrWrongPath
- }
- return nmItm.Set(path, val)
- }
-
- // standard handling
- if len(path) == 1 { // always overwrite for single path
- nm[path[0].Field] = val
- if !has {
- added = true
- }
- return
- }
- // from here we should deal only with navmaps due to multiple path
- if !has {
- nmItm = NavigableMap2{}
- nm[path[0].Field] = nmItm
- }
- if nmItm.Type() != NMMapType { // do not try to overwrite an interface
- return false, ErrWrongPath
- }
- return nmItm.Set(path[1:], val)
-}
-
-// Remove removes the item for the given path
-func (nm NavigableMap2) Remove(path PathItems) (err error) {
- if len(path) == 0 {
- return ErrWrongPath
- }
- el, has := nm[path[0].Field]
- if !has {
- return // already removed
- }
- if len(path) == 1 {
- if path[0].Index != nil {
- if el.Type() != NMSliceType {
- return ErrWrongPath
- }
- // this should not return error
- // but in case it does we propagate it further
- err = el.Remove(path)
- if el.Empty() {
- delete(nm, path[0].Field)
- }
- return
- }
- delete(nm, path[0].Field)
- return
- }
- if path[0].Index != nil {
- if el.Type() != NMSliceType {
- return ErrWrongPath
- }
- if err = el.Remove(path); err != nil {
- return
- }
- if el.Empty() {
- delete(nm, path[0].Field)
- }
- return
- }
- if el.Type() != NMMapType {
- return ErrWrongPath
- }
- if err = el.Remove(path[1:]); err != nil {
- return
- }
- if el.Empty() {
- delete(nm, path[0].Field)
- }
- return
-}
-
-// Type returns the type of the NM map
-func (nm NavigableMap2) Type() NMType {
- return NMMapType
-}
-
-// Empty returns true if the NM is empty(no data)
-func (nm NavigableMap2) Empty() bool {
- return len(nm) == 0
-}
-
-// Len returns the lenght of the map
-func (nm NavigableMap2) Len() int {
- return len(nm)
-}
-
-// FieldAsInterface returns the interface at the path
-// Is used by AgentRequest FieldAsInterface
-func (nm NavigableMap2) FieldAsInterface(fldPath []string) (str any, err error) {
- var nmi NMInterface
- if nmi, err = nm.Field(NewPathItems(fldPath)); err != nil {
- return
- }
- return nmi.Interface(), nil
-}
-
-// FieldAsString returns the string at the path
-// Used only to implement the DataProvider interface
-func (nm NavigableMap2) FieldAsString(fldPath []string) (str string, err error) {
- var val any
- val, err = nm.FieldAsInterface(fldPath)
- if err != nil {
- return
- }
- return IfaceAsString(val), nil
-}
-
-// RemoteHost is part of dataStorage interface
-func (NavigableMap2) RemoteHost() net.Addr {
- return LocalAddr()
-}
-
-
-
/*
-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 utils
-
-// NewNMData returns the interface wraped in NMInterface struture
-func NewNMData(val any) *NMData { return &NMData{data: val} }
-
-// NMData most basic NM structure
-type NMData struct{ data any }
-
-func (nmi *NMData) String() string {
- return IfaceAsString(nmi.data)
-}
-
-// Interface returns the wraped interface
-func (nmi *NMData) Interface() any {
- return nmi.data
-}
-
-// Field is not implemented only used in order to implement the NM interface
-func (nmi *NMData) Field(path PathItems) (val NMInterface, err error) {
- return nil, ErrNotImplemented
-}
-
-// Set sets the wraped interface when the path is empty
-// This behaivior is in order to modify the wraped interface
-// witout aserting the type of the NMInterface
-func (nmi *NMData) Set(path PathItems, val NMInterface) (addedNew bool, err error) {
- if len(path) != 0 {
- return false, ErrWrongPath
- }
- nmi.data = val.Interface()
- return
-}
-
-// Remove is not implemented only used in order to implement the NM interface
-func (nmi *NMData) Remove(path PathItems) (err error) {
- return ErrNotImplemented
-}
-
-// Type returns the type of the NM interface
-func (nmi *NMData) Type() NMType {
- return NMDataType
-}
-
-// Empty returns true if the NM is empty(no data)
-func (nmi *NMData) Empty() bool {
- return nmi == nil || nmi.data == nil
-}
-
-// Len is not implemented only used in order to implement the NM interface
-func (nmi *NMData) Len() int {
- return 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 utils
-
-// NMSlice is the basic slice of NM interface
-type NMSlice []NMInterface
-
-func (nms *NMSlice) String() (out string) {
- for _, v := range *nms {
- out += "," + v.String()
- }
- if len(out) == 0 {
- return "[]"
- }
- out = out[1:]
- return "[" + out + "]"
-}
-
-// Interface returns itself
-func (nms *NMSlice) Interface() any {
- return nms
-}
-
-// Field returns the item on the given path
-// for NMSlice only the Index field is considered
-func (nms *NMSlice) Field(path PathItems) (val NMInterface, err error) {
- if len(path) == 0 {
- return nil, ErrWrongPath
- }
- if nms.Empty() || path[0].Index == nil {
- return nil, ErrNotFound
- }
- idx := *path[0].Index
- if idx < 0 {
- idx = len(*nms) + idx
- }
- if idx < 0 || idx >= len(*nms) {
- return nil, ErrNotFound
- }
- if len(path) == 1 {
- return (*nms)[idx], nil
- }
- return (*nms)[idx].Field(path[1:])
-}
-
-// Set sets the value for the given index
-func (nms *NMSlice) Set(path PathItems, val NMInterface) (addedNew bool, err error) {
- if len(path) == 0 || path[0].Index == nil {
- return false, ErrWrongPath
- }
- idx := *path[0].Index
- if idx == len(*nms) { // append element
- addedNew = true
- if len(path) == 1 {
- *nms = append(*nms, val)
- return
- }
- nel := NavigableMap2{}
- if _, err = nel.Set(path[1:], val); err != nil {
- return
- }
- *nms = append(*nms, nel)
- return
- }
- if idx < 0 {
- idx = len(*nms) + idx
- }
- if idx < 0 || idx >= len(*nms) {
- return false, ErrWrongPath
- }
- path[0].Index = &idx
- if len(path) == 1 {
- (*nms)[idx] = val
- return
- }
- if (*nms)[idx].Type() == NMSliceType {
- return false, ErrWrongPath
- }
- return (*nms)[idx].Set(path[1:], val)
-}
-
-// Remove removes the item for the given index
-func (nms *NMSlice) Remove(path PathItems) (err error) {
- if len(path) == 0 || path[0].Index == nil {
- return ErrWrongPath
- }
- idx := *path[0].Index
- if idx < 0 {
- idx = len(*nms) + idx
- }
- if idx < 0 || idx >= len(*nms) { // already removed
- return
- }
- path[0].Index = &idx
- if len(path) == 1 {
- *nms = append((*nms)[:idx], (*nms)[idx+1:]...)
- return
- }
- if (*nms)[idx].Type() != NMMapType {
- return ErrWrongPath
- }
- if err = (*nms)[idx].Remove(path[1:]); err != nil {
- return
- }
- if (*nms)[idx].Empty() {
- *nms = append((*nms)[:idx], (*nms)[idx+1:]...)
- }
- return
-}
-
-// Type returns the type of the NM slice
-func (nms NMSlice) Type() NMType {
- return NMSliceType
-}
-
-// Empty returns true if the NM is empty(no data)
-func (nms NMSlice) Empty() bool {
- return len(nms) == 0
-}
-
-// Len returns the lenght of the slice
-func (nms *NMSlice) Len() int {
- return len(*nms)
-}
-
-
-
/*
-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 utils
-
-// OrderedMap is a map that maintains the order of its key-value pairs.
-type OrderedMap[K comparable, V any] struct {
- keys []K // keys holds the keys in order of their insertion.
- values map[K]V // values is a map of key-value pairs.
-}
-
-// NewOrderedMap creates a new ordered map and returns a pointer to it.
-func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
- return &OrderedMap[K, V]{
- keys: make([]K, 0), // Initialize an empty slice for keys.
- values: make(map[K]V), // Initialize an empty map for key-value pairs.
- }
-}
-
-// Set adds a new key-value pair to the ordered map. If the key already exists, it updates the value.
-func (om *OrderedMap[K, V]) Set(key K, value V) {
- // If the key does not exist in the map, append it to the keys slice.
- if _, exists := om.values[key]; !exists {
- om.keys = append(om.keys, key)
- }
- // Add or update the value for the key in the map.
- om.values[key] = value
-}
-
-// Get retrieves the value associated with the given key from the ordered map.
-// It returns the value and a boolean indicating whether the key exists in the map.
-func (om *OrderedMap[K, V]) Get(key K) (V, bool) {
- // Retrieve the value for the key from the map.
- val, ok := om.values[key]
- return val, ok
-}
-
-// Delete removes the key-value pair associated with the given key from the ordered map.
-func (om *OrderedMap[K, V]) Delete(key K) {
- // Iterate over the keys slice to find the key to delete.
- for i, k := range om.keys {
- // When the key is found, remove it from the slice.
- if k == key {
- om.keys = append(om.keys[:i], om.keys[i+1:]...)
- break
- }
- }
- // Remove the key-value pair from the map.
- delete(om.values, key)
-}
-
-// Keys returns all keys of the ordered map in order of their insertion.
-func (om *OrderedMap[K, V]) Keys() []K {
- return om.keys
-}
-
-// Values returns all values of the ordered map in the order of their corresponding keys' insertion.
-func (om *OrderedMap[K, V]) Values() []V {
- // Initialize an empty slice to hold the values.
- vals := make([]V, 0, len(om.values))
-
- // Iterate over the keys in order and append the corresponding value to the values slice.
- for _, key := range om.keys {
- vals = append(vals, om.values[key])
- }
- return vals
-}
-
-
-
/*
-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 utils
-
-import (
- "net"
- "strings"
-)
-
-// NewOrderedNavigableMap initializates a structure of OrderedNavigableMap with a NavigableMap2
-func NewOrderedNavigableMap() *OrderedNavigableMap {
- return &OrderedNavigableMap{
- nm: NavigableMap2{},
- orderIdx: NewPathItemList(),
- orderRef: make(map[string][]*PathItemElement),
- }
-}
-
-// OrderedNavigableMap is the same as NavigableMap2 but keeps the order of fields
-type OrderedNavigableMap struct {
- nm NMInterface
- orderIdx *PathItemList
- orderRef map[string][]*PathItemElement
-}
-
-// String returns the map as json string
-func (onm *OrderedNavigableMap) String() string {
- return onm.nm.String()
-}
-
-// GetFirstElement returns the first element from the order
-func (onm *OrderedNavigableMap) GetFirstElement() *PathItemElement {
- return onm.orderIdx.Front()
-}
-
-// Interface returns navigble map that's inside
-func (onm *OrderedNavigableMap) Interface() any {
- return onm.nm
-}
-
-// Field returns the item on the given path
-func (onm *OrderedNavigableMap) Field(fldPath PathItems) (val NMInterface, err error) {
- return onm.nm.Field(fldPath)
-}
-
-// Type returns the type of the NM map
-func (onm *OrderedNavigableMap) Type() NMType {
- return onm.nm.Type()
-}
-
-// Empty returns true if the NM is empty(no data)
-func (onm *OrderedNavigableMap) Empty() bool {
- return onm.nm.Empty()
-}
-
-// Remove removes the item for the given path and updates the order
-func (onm *OrderedNavigableMap) Remove(fullPath *FullPath) (err error) {
- path := stripIdxFromLastPathElm(fullPath.Path)
- if path == EmptyString || fullPath.PathItems[len(fullPath.PathItems)-1].Index != nil {
- return ErrWrongPath
- }
- if err = onm.nm.Remove(fullPath.PathItems); err != nil {
- return
- }
-
- for idxPath, slcIdx := range onm.orderRef {
- if !strings.HasPrefix(idxPath, path) {
- continue
- }
- for _, el := range slcIdx {
- onm.orderIdx.Remove(el)
- }
- delete(onm.orderRef, idxPath)
- }
- return
-}
-
-// Set sets the value at the given path
-// this used with full path and the processed path to not calculate them for every set
-func (onm *OrderedNavigableMap) Set(fullPath *FullPath, val NMInterface) (addedNew bool, err error) {
- if fullPath == nil || len(fullPath.PathItems) == 0 {
- return false, ErrWrongPath
- }
- if addedNew, err = onm.nm.Set(fullPath.PathItems, val); err != nil {
- return
- }
-
- var pathItmsSet []PathItems // can be multiples if we need to inflate due to missing Index in slice set
- var nonIndexedSlcPath bool
- if val.Type() == NMSliceType && fullPath.PathItems[len(fullPath.PathItems)-1].Index == nil { // special case when we overwrite with a slice without specifying indexes
- nonIndexedSlcPath = true
- pathItmsSet = make([]PathItems, len(*val.(*NMSlice)))
- for i := 0; i < val.Len(); i++ {
- pathItms := fullPath.PathItems.Clone()
- pathItms[len(pathItms)-1].Index = IntPointer(i)
- pathItmsSet[i] = pathItms
- }
- } else {
- pathItmsSet = []PathItems{fullPath.PathItems}
- }
- path := stripIdxFromLastPathElm(fullPath.Path)
- if !addedNew && nonIndexedSlcPath { // cleanup old references since the value is being overwritten
- for idxPath, slcIdx := range onm.orderRef {
- if !strings.HasPrefix(idxPath, path) {
- continue
- }
- for _, el := range slcIdx {
- onm.orderIdx.Remove(el)
- }
- delete(onm.orderRef, idxPath)
- }
- }
- _, hasRef := onm.orderRef[path]
- for _, pathItms := range pathItmsSet {
- if addedNew || !hasRef {
- onm.orderRef[path] = append(onm.orderRef[path], onm.orderIdx.PushBack(pathItms))
- } else {
- onm.orderIdx.MoveToBack(onm.orderRef[path][len(onm.orderRef[path])-1])
- }
- }
- return
-}
-
-// Len returns the lenght of the map
-func (onm OrderedNavigableMap) Len() int {
- return onm.nm.Len()
-}
-
-// FieldAsString returns thevalue from path as string
-func (onm *OrderedNavigableMap) FieldAsString(fldPath []string) (str string, err error) {
- var val NMInterface
- val, err = onm.nm.Field(NewPathItems(fldPath))
- if err != nil {
- return
- }
- return IfaceAsString(val.Interface()), nil
-}
-
-// FieldAsInterface returns the interface at the path
-func (onm *OrderedNavigableMap) FieldAsInterface(fldPath []string) (str any, err error) {
- var val NMInterface
- val, err = onm.nm.Field(NewPathItems(fldPath))
- if err != nil {
- return
- }
- return val.Interface(), nil
-}
-
-// RemoteHost is part of dataStorage interface
-func (OrderedNavigableMap) RemoteHost() net.Addr {
- return LocalAddr()
-}
-
-// GetOrder returns the elements order as a slice
-// use this only for testing
-func (onm *OrderedNavigableMap) GetOrder() (order []PathItems) {
- for el := onm.GetFirstElement(); el != nil; el = el.Next() {
- order = append(order, el.Value)
- }
- return
-}
-
-// RemoveAll will clean the data and the odrder from OrderedNavigableMap
-func (onm *OrderedNavigableMap) RemoveAll() {
- onm.nm = NavigableMap2{}
- onm.orderIdx = NewPathItemList()
- onm.orderRef = make(map[string][]*PathItemElement)
-}
-
-
-
/*
-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 utils
-
-import (
- "strconv"
- "strings"
-)
-
-// stripIdxFromLastPathElm will remove the index from the last path element
-func stripIdxFromLastPathElm(path string) string {
- lastDotIdx := strings.LastIndexByte(path, '.')
- lastIdxStart := strings.LastIndexByte(path, '[')
- if lastIdxStart == -1 ||
- (lastDotIdx != -1 && lastDotIdx > lastIdxStart) {
- return path
- }
- return path[:lastIdxStart]
-}
-
-// FullPath is the path to the item with all the needed fields
-type FullPath struct {
- PathItems PathItems
- Path string
-}
-
-// NewPathItems returns the computed PathItems out of slice one
-func NewPathItems(path []string) (pItms PathItems) {
- pItms = make(PathItems, len(path))
- for i, v := range path {
- field, indx := GetPathIndex(v)
- pItms[i] = PathItem{
- Field: field,
- Index: indx,
- }
- }
- return
-}
-
-// PathItems a list of PathItem used to describe the path to an item from a NavigableMap
-type PathItems []PathItem
-
-// Clone creates a copy
-func (path PathItems) Clone() (c PathItems) {
- if path == nil {
- return
- }
- c = make(PathItems, len(path))
- for i, v := range path {
- c[i] = v.Clone()
- }
- return
-}
-
-func (path PathItems) String() (out string) {
- for _, v := range path {
- out += NestingSep + v.String()
- }
- if out == "" {
- return
- }
- return out[1:]
-
-}
-
-// PathItem used by the NM interface to store the path information
-type PathItem struct {
- Field string
- Index *int
-}
-
-// Equal returns true if p==p2
-func (p PathItem) Equal(p2 PathItem) bool {
- if p.Field != p2.Field {
- return false
- }
- if p.Index == nil && p2.Index == nil {
- return true
- }
- if p.Index != nil && p2.Index != nil {
- return *p.Index == *p2.Index
- }
- return false
-}
-
-func (p PathItem) String() (out string) {
- out = p.Field
- if p.Index != nil {
- out += IdxStart + strconv.Itoa(*p.Index) + IdxEnd
- }
- return
-}
-
-// Clone creates a copy
-func (p PathItem) Clone() (c PathItem) {
- // if p == nil {
- // return
- // }
- c.Field = p.Field
- if p.Index != nil {
- c.Index = IntPointer(*p.Index)
- }
- return
-}
-
-// GetPathIndex returns the path and index if index present
-// path[index]=>path,index
-// path=>path,nil
-func GetPathIndex(spath string) (opath string, idx *int) {
- idxStart := strings.Index(spath, IdxStart)
- if idxStart == -1 || !strings.HasSuffix(spath, IdxEnd) {
- return spath, nil
- }
- slctr := spath[idxStart+1 : len(spath)-1]
- opath = spath[:idxStart]
- // if strings.HasPrefix(slctr, DynamicDataPrefix) {
- // return
- // }
- idxVal, err := strconv.Atoi(slctr)
- if err != nil {
- return spath, nil
- }
- return opath, &idxVal
-}
-
-func GetPathWithoutIndex(spath string) (opath string) {
- idxStart := strings.LastIndex(spath, IdxStart)
- if idxStart == -1 || !strings.HasSuffix(spath, IdxEnd) {
- return spath
- }
- opath = spath[:idxStart]
- return
-}
-
-
-
/*
-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 utils
-
-// PathItemElement is an element of a linked list.
-// Inspired by Go's double linked list
-type PathItemElement struct {
- // Next and previous pointers in the doubly-linked list of elements.
- // To simplify the implementation, internally a list l is implemented
- // as a ring, such that &l.root is both the next element of the last
- // list element (l.Back()) and the previous element of the first list
- // element (l.Front()).
- next, prev *PathItemElement
-
- // The list to which this element belongs.
- list *PathItemList
-
- // The value stored with this element.
- Value PathItems
-}
-
-// Next returns the next list element or nil.
-func (e *PathItemElement) Next() *PathItemElement {
- if p := e.next; e.list != nil && p != &e.list.root {
- return p
- }
- return nil
-}
-
-// Prev returns the previous list element or nil.
-func (e *PathItemElement) Prev() *PathItemElement {
- if p := e.prev; e.list != nil && p != &e.list.root {
- return p
- }
- return nil
-}
-
-// PathItemList represents a doubly linked list.
-// The zero value for PathItemList is an empty list ready to use.
-type PathItemList struct {
- root PathItemElement // sentinel list element, only &root, root.prev, and root.next are used
- len int // current list length excluding (this) sentinel element
-}
-
-// Init initializes or clears list l.
-func (l *PathItemList) Init() *PathItemList {
- l.root.next = &l.root
- l.root.prev = &l.root
- l.len = 0
- return l
-}
-
-// NewPathItemList returns an initialized list.
-func NewPathItemList() *PathItemList { return new(PathItemList).Init() }
-
-// Len returns the number of elements of list l.
-// The complexity is O(1).
-func (l *PathItemList) Len() int { return l.len }
-
-// Front returns the first element of list l or nil if the list is empty.
-func (l *PathItemList) Front() *PathItemElement {
- if l.len == 0 {
- return nil
- }
- return l.root.next
-}
-
-// Back returns the last element of list l or nil if the list is empty.
-func (l *PathItemList) Back() *PathItemElement {
- if l.len == 0 {
- return nil
- }
- return l.root.prev
-}
-
-// lazyInit lazily initializes a zero PathItemList value.
-func (l *PathItemList) lazyInit() {
- if l.root.next == nil {
- l.Init()
- }
-}
-
-// insert inserts e after at, increments l.len, and returns e.
-func (l *PathItemList) insert(e, at *PathItemElement) *PathItemElement {
- n := at.next
- at.next = e
- e.prev = at
- e.next = n
- n.prev = e
- e.list = l
- l.len++
- return e
-}
-
-// insertValue is a convenience wrapper for insert(&PathItemElement{Value: v}, at).
-func (l *PathItemList) insertValue(v PathItems, at *PathItemElement) *PathItemElement {
- return l.insert(&PathItemElement{Value: v}, at)
-}
-
-// remove removes e from its list, decrements l.len, and returns e.
-func (l *PathItemList) remove(e *PathItemElement) *PathItemElement {
- e.prev.next = e.next
- e.next.prev = e.prev
- e.next = nil // avoid memory leaks
- e.prev = nil // avoid memory leaks
- e.list = nil
- l.len--
- return e
-}
-
-// move moves e to next to at and returns e.
-func (l *PathItemList) move(e, at *PathItemElement) *PathItemElement {
- if e == at {
- return e
- }
- e.prev.next = e.next
- e.next.prev = e.prev
-
- n := at.next
- at.next = e
- e.prev = at
- e.next = n
- n.prev = e
-
- return e
-}
-
-// Remove removes e from l if e is an element of list l.
-// It returns the element value e.Value.
-// The element must not be nil.
-func (l *PathItemList) Remove(e *PathItemElement) PathItems {
- if e.list == l {
- // if e.list == l, l must have been initialized when e was inserted
- // in l or l == nil (e is a zero PathItemElement) and l.remove will crash
- l.remove(e)
- }
- return e.Value
-}
-
-// PushFront inserts a new element e with value v at the front of list l and returns e.
-func (l *PathItemList) PushFront(v PathItems) *PathItemElement {
- l.lazyInit()
- return l.insertValue(v, &l.root)
-}
-
-// PushBack inserts a new element e with value v at the back of list l and returns e.
-func (l *PathItemList) PushBack(v PathItems) *PathItemElement {
- l.lazyInit()
- return l.insertValue(v, l.root.prev)
-}
-
-// InsertBefore inserts a new element e with value v immediately before mark and returns e.
-// If mark is not an element of l, the list is not modified.
-// The mark must not be nil.
-func (l *PathItemList) InsertBefore(v PathItems, mark *PathItemElement) *PathItemElement {
- if mark.list != l {
- return nil
- }
- // see comment in PathItemList.Remove about initialization of l
- return l.insertValue(v, mark.prev)
-}
-
-// InsertAfter inserts a new element e with value v immediately after mark and returns e.
-// If mark is not an element of l, the list is not modified.
-// The mark must not be nil.
-func (l *PathItemList) InsertAfter(v PathItems, mark *PathItemElement) *PathItemElement {
- if mark.list != l {
- return nil
- }
- // see comment in PathItemList.Remove about initialization of l
- return l.insertValue(v, mark)
-}
-
-// MoveToFront moves element e to the front of list l.
-// If e is not an element of l, the list is not modified.
-// The element must not be nil.
-func (l *PathItemList) MoveToFront(e *PathItemElement) {
- if e.list != l || l.root.next == e {
- return
- }
- // see comment in PathItemList.Remove about initialization of l
- l.move(e, &l.root)
-}
-
-// MoveToBack moves element e to the back of list l.
-// If e is not an element of l, the list is not modified.
-// The element must not be nil.
-func (l *PathItemList) MoveToBack(e *PathItemElement) {
- if e.list != l || l.root.prev == e {
- return
- }
- // see comment in PathItemList.Remove about initialization of l
- l.move(e, l.root.prev)
-}
-
-// MoveBefore moves element e to its new position before mark.
-// If e or mark is not an element of l, or e == mark, the list is not modified.
-// The element and mark must not be nil.
-func (l *PathItemList) MoveBefore(e, mark *PathItemElement) {
- if e.list != l || e == mark || mark.list != l {
- return
- }
- l.move(e, mark.prev)
-}
-
-// MoveAfter moves element e to its new position after mark.
-// If e or mark is not an element of l, or e == mark, the list is not modified.
-// The element and mark must not be nil.
-func (l *PathItemList) MoveAfter(e, mark *PathItemElement) {
- if e.list != l || e == mark || mark.list != l {
- return
- }
- l.move(e, mark)
-}
-
-// PushBackList inserts a copy of an other list at the back of list l.
-// The lists l and other may be the same. They must not be nil.
-func (l *PathItemList) PushBackList(other *PathItemList) {
- l.lazyInit()
- for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
- l.insertValue(e.Value, l.root.prev)
- }
-}
-
-// PushFrontList inserts a copy of an other list at the front of list l.
-// The lists l and other may be the same. They must not be nil.
-func (l *PathItemList) PushFrontList(other *PathItemList) {
- l.lazyInit()
- for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() {
- l.insertValue(e.Value, &l.root)
- }
-}
-
-
-
/*
-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 utils
-
-import (
- "errors"
- "fmt"
- "net"
- "reflect"
- "strconv"
- "time"
-)
-
-// StringToInterface will parse string into supported types
-// if no other conversion possible, original string will be returned
-func StringToInterface(s string) any {
- // int64
- if i, err := strconv.ParseInt(s, 10, 64); err == nil {
- return i
- }
- // bool
- if b, err := strconv.ParseBool(s); err == nil {
- return b
- }
- // float64
- if f, err := strconv.ParseFloat(s, 64); err == nil {
- return f
- }
- // time.Time
- if t, err := ParseTimeDetectLayout(s, "Local"); err == nil {
- return t
- }
- // time.Duration
- if d, err := time.ParseDuration(s); err == nil {
- return d
- }
- // string
- return s
-}
-
-// ReflectFieldInterface parses intf attepting to return the field value or error otherwise
-// Supports "ExtraFields" where additional fields are dynamically inserted in map with field name: extraFieldsLabel
-func ReflectFieldInterface(intf any, fldName, extraFieldsLabel string) (retIf any, err error) {
- v := reflect.ValueOf(intf)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- var field reflect.Value
- switch v.Kind() {
- case reflect.Struct:
- field = v.FieldByName(fldName)
- case reflect.Map:
- field = v.MapIndex(reflect.ValueOf(fldName))
- if !field.IsValid() { // Not looking in extra fields anymore
- return nil, ErrNotFound
- }
- default:
- return nil, fmt.Errorf("Unsupported field kind: %v", v.Kind())
- }
-
- if !field.IsValid() {
- if extraFieldsLabel == "" {
- return nil, ErrNotFound
- }
- mpVal := v.FieldByName(extraFieldsLabel)
- if !mpVal.IsValid() || mpVal.Kind() != reflect.Map {
- return nil, ErrNotFound
- }
- field = mpVal.MapIndex(reflect.ValueOf(fldName))
- if !field.IsValid() {
- return nil, ErrNotFound
- }
- }
- return field.Interface(), nil
-}
-
-// ReflectFieldAsString parses intf and attepting to return the field as string or error otherwise
-// Supports "ExtraFields" where additional fields are dynamically inserted in map with field name: extraFieldsLabel
-func ReflectFieldAsString(intf any, fldName, extraFieldsLabel string) (string, error) {
- field, err := ReflectFieldInterface(intf, fldName, extraFieldsLabel)
- if err != nil {
- return "", err
- }
- vOf := reflect.ValueOf(field)
- switch vOf.Kind() {
- case reflect.String:
- return vOf.String(), nil
- case reflect.Int, reflect.Int64:
- return strconv.FormatInt(vOf.Int(), 10), nil
- case reflect.Float64:
- return strconv.FormatFloat(vOf.Float(), 'f', -1, 64), nil
- case reflect.Interface:
- return IfaceAsString(field), nil
- default:
- return "", fmt.Errorf("Cannot convert to string field type: %s", vOf.Kind().String())
- }
-}
-
-func IfaceAsTime(itm any, timezone string) (t time.Time, err error) {
- switch val := itm.(type) {
- case time.Time:
- return val, nil
- case string:
- return ParseTimeDetectLayout(val, timezone)
- default:
- err = fmt.Errorf("cannot convert field: %+v to time.Time", itm)
- }
- return
-}
-
-func IfaceAsDuration(itm any) (d time.Duration, err error) {
- switch it := itm.(type) {
- case time.Duration:
- return it, nil
- case int: // check every int type
- return time.Duration(int64(it)), nil
- case int8:
- return time.Duration(int64(it)), nil
- case int16:
- return time.Duration(int64(it)), nil
- case int32:
- return time.Duration(int64(it)), nil
- case int64:
- return time.Duration(it), nil
- case uint:
- return time.Duration(int64(it)), nil
- case uint8:
- return time.Duration(int64(it)), nil
- case uint16:
- return time.Duration(int64(it)), nil
- case uint32:
- return time.Duration(int64(it)), nil
- case uint64:
- return time.Duration(int64(it)), nil
- case float32: // automatically hitting here also ints
- return time.Duration(int64(it)), nil
- case float64: // automatically hitting here also ints
- return time.Duration(int64(it)), nil
- case string:
- return ParseDurationWithNanosecs(it)
- default:
- err = fmt.Errorf("cannot convert field: %+v to time.Duration", it)
- }
- return
-}
-
-func IfaceAsInt64(itm any) (i int64, err error) {
- switch it := itm.(type) {
- case int:
- return int64(it), nil
- case time.Duration:
- return it.Nanoseconds(), nil
- case int32:
- return int64(it), nil
- case int64:
- return it, nil
- case string:
- return strconv.ParseInt(it, 10, 64)
- default:
- err = fmt.Errorf("cannot convert field: %+v to int", it)
- }
- return
-}
-
-// same function as IfaceAsInt64 but if the value is float round it to int64 instead of returning error
-func IfaceAsTInt64(itm any) (i int64, err error) {
- switch it := itm.(type) {
- case int:
- return int64(it), nil
- case time.Duration:
- return it.Nanoseconds(), nil
- case int32:
- return int64(it), nil
- case int64:
- return it, nil
- case float32:
- return int64(it), nil
- case float64:
- return int64(it), nil
- case string:
- return strconv.ParseInt(it, 10, 64)
- default:
- err = fmt.Errorf("cannot convert field<%T>: %+v to int", it, it)
- }
- return
-}
-
-func IfaceAsFloat64(itm any) (f float64, err error) {
- switch it := itm.(type) {
- case float64:
- return it, nil
- case time.Duration:
- return float64(it.Nanoseconds()), nil
- case int:
- return float64(it), nil
- case int64:
- return float64(it), nil
- case string:
- return strconv.ParseFloat(it, 64)
- default:
- err = fmt.Errorf("cannot convert field: %+v to float64", it)
- }
- return
-}
-
-func IfaceAsBool(itm any) (b bool, err error) {
- switch val := itm.(type) {
- case bool:
- return val, nil
- case string:
- return strconv.ParseBool(val)
- case int:
- return val > 0, nil
- case int64:
- return val > 0, nil
- case float64:
- return val > 0, nil
- default:
- err = fmt.Errorf("cannot convert field: %+v to bool", itm)
- }
- return
-}
-
-func IfaceAsString(fld any) (out string) {
- switch value := fld.(type) {
- case nil:
- return
- case int:
- return strconv.Itoa(value)
- case int32:
- return strconv.FormatInt(int64(value), 10)
- case int64:
- return strconv.FormatInt(value, 10)
- case uint32:
- return strconv.FormatUint(uint64(value), 10)
- case uint64:
- return strconv.FormatUint(value, 10)
- case bool:
- return strconv.FormatBool(value)
- case float32:
- return strconv.FormatFloat(float64(value), 'f', -1, 64)
- case float64:
- return strconv.FormatFloat(value, 'f', -1, 64)
- case []uint8:
- return string(value) // byte is an alias for uint8 conversions implicit
- case time.Duration:
- return value.String()
- case time.Time:
- return value.Format(time.RFC3339)
- case net.IP:
- return value.String()
- case string:
- return value
- case NMInterface:
- return value.String()
- default: // Maybe we are lucky and the value converts to string
- return ToJSON(fld)
- }
-}
-
-// IfaceAsSliceString is trying to convert the interface to a slice of strings
-func IfaceAsSliceString(fld any) (out []string, err error) {
- switch value := fld.(type) {
- case nil:
- return
- case []int:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = strconv.Itoa(val)
- }
- case []int32:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = strconv.FormatInt(int64(val), 10)
- }
- case []int64:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = strconv.FormatInt(val, 10)
- }
- case []uint:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = strconv.FormatUint(uint64(val), 10)
- }
- case []uint32:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = strconv.FormatUint(uint64(val), 10)
- }
- case []uint64:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = strconv.FormatUint(val, 10)
- }
- case []bool:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = strconv.FormatBool(val)
- }
- case []float32:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = strconv.FormatFloat(float64(val), 'f', -1, 64)
- }
- case []float64:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = strconv.FormatFloat(val, 'f', -1, 64)
- }
- case [][]uint8:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = string(val) // byte is an alias for uint8 conversions implicit
- }
- case []time.Duration:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = val.String()
- }
- case []time.Time:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = val.Format(time.RFC3339)
- }
- case []net.IP:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = val.String()
- }
- case []string:
- out = value
- case []any:
- out = make([]string, len(value))
- for i, val := range value {
- out[i] = IfaceAsString(val)
- }
- default:
- err = fmt.Errorf("cannot convert field: %T to []string", value)
- }
- return
-}
-
-// AsMapStringIface converts an item (mostly struct) as map[string]any
-func AsMapStringIface(item any) (map[string]any, error) {
- out := make(map[string]any)
- v := reflect.ValueOf(item)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- if v.Kind() != reflect.Struct { // Only structs for now
- return nil, fmt.Errorf("AsMapStringIface only accepts structs; got %T", v)
- }
- typ := v.Type()
- for i := 0; i < v.NumField(); i++ {
- out[typ.Field(i).Name] = v.Field(i).Interface()
- }
- return out, nil
-}
-
-func GetUniformType(item any) (any, error) {
- valItm := reflect.ValueOf(item)
- switch valItm.Kind() { // convert evreting to float64
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return float64(valItm.Int()), nil
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return float64(valItm.Uint()), nil
- case reflect.Float32, reflect.Float64:
- return valItm.Float(), nil
- case reflect.Struct: // used only for time
- return valItm.Interface(), nil
- default:
- return nil, errors.New("incomparable")
- }
- return item, nil
-}
-
-func GetBasicType(item any) any {
- valItm := reflect.ValueOf(item)
- switch valItm.Kind() { // convert evreting to float64
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return valItm.Int()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return valItm.Uint()
- case reflect.Float32, reflect.Float64:
- return valItm.Float()
- default:
- return item
- }
- return item
-}
-
-// GreaterThan attempts to compare two items
-// returns the result or error if not comparable
-func GreaterThan(item, oItem any, orEqual bool) (gte bool, err error) {
- item = GetBasicType(item)
- oItem = GetBasicType(oItem)
- typItem := reflect.TypeOf(item)
- typOItem := reflect.TypeOf(oItem)
- if typItem != typOItem {
- if item, err = GetUniformType(item); err == nil { // overwrite type only if possible
- typItem = reflect.TypeOf(item)
- }
- if oItem, err = GetUniformType(oItem); err == nil {
- typOItem = reflect.TypeOf(oItem)
- }
- }
- if !typItem.Comparable() ||
- !typOItem.Comparable() ||
- typItem != typOItem {
- return false, fmt.Errorf("incomparable: <%+v> with <%+v>", item, oItem)
- }
- switch tVal := item.(type) {
- case float64:
- tOVal := oItem.(float64)
- if orEqual {
- gte = tVal >= tOVal
- } else {
- gte = tVal > tOVal
- }
- case uint64:
- tOVal := oItem.(uint64)
- if orEqual {
- gte = tVal >= tOVal
- } else {
- gte = tVal > tOVal
- }
- case int64:
- tOVal := oItem.(int64)
- if orEqual {
- gte = tVal >= tOVal
- } else {
- gte = tVal > tOVal
- }
- case time.Time:
- tOVal := oItem.(time.Time)
- if orEqual {
- gte = tVal == tOVal
- }
- if !gte {
- gte = tVal.After(tOVal)
- }
- default: // unsupported comparison
- err = fmt.Errorf("unsupported comparison type: %v, kind: %v", typItem, typItem.Kind())
- }
- return
-}
-
-func EqualTo(item, oItem any) (eq bool, err error) {
- item = GetBasicType(item)
- oItem = GetBasicType(oItem)
- typItem := reflect.TypeOf(item)
- typOItem := reflect.TypeOf(oItem)
- if typItem != typOItem {
- if item, err = GetUniformType(item); err == nil { // overwrite type only if possible
- typItem = reflect.TypeOf(item)
- }
- if oItem, err = GetUniformType(oItem); err == nil {
- typOItem = reflect.TypeOf(oItem)
- }
- }
- if !typItem.Comparable() ||
- !typOItem.Comparable() ||
- typItem != typOItem {
- return false, fmt.Errorf("incomparable: <%+v> with <%+v>", item, oItem)
- }
- switch tVal := item.(type) {
- case float64:
- tOVal := oItem.(float64)
- eq = tVal == tOVal
- case uint64:
- tOVal := oItem.(uint64)
- eq = tVal == tOVal
- case int64:
- tOVal := oItem.(int64)
- eq = tVal == tOVal
- case time.Time:
- tOVal := oItem.(time.Time)
- eq = tVal == tOVal
- case string:
- tOVal := oItem.(string)
- eq = tVal == tOVal
- default: // unsupported comparison
- err = fmt.Errorf("unsupported comparison type: %v, kind: %v", typItem, typItem.Kind())
- }
- return
-}
-
-// Sum attempts to sum multiple items
-// returns the result or error if not comparable
-func Sum(items ...any) (sum any, err error) {
- //we need at least 2 items to sum them
- if len(items) < 2 {
- return nil, ErrNotEnoughParameters
- }
-
- switch dt := items[0].(type) {
- case time.Duration:
- sum = dt
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsDuration(item); err != nil {
- return nil, err
- } else {
- sum = sum.(time.Duration) + itmVal
- }
- }
- case time.Time:
- sum = dt
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsDuration(item); err != nil {
- return nil, err
- } else {
- sum = sum.(time.Time).Add(itmVal)
- }
- }
- case float64:
- sum = dt
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsFloat64(item); err != nil {
- return nil, err
- } else {
- sum = sum.(float64) + itmVal
- }
- }
- case int64:
- sum = dt
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsInt64(item); err != nil {
- return nil, err
- } else {
- sum = sum.(int64) + itmVal
- }
- }
- case int:
- // need explicit conversion for int
- if firstItmVal, err := IfaceAsInt64(dt); err != nil {
- return nil, err
- } else {
- sum = firstItmVal
- }
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsInt64(item); err != nil {
- return nil, err
- } else {
- sum = sum.(int64) + itmVal
- }
- }
- }
- return
-}
-
-// Difference attempts to sum multiple items
-// returns the result or error if not comparable
-func Difference(items ...any) (diff any, err error) {
- //we need at least 2 items to diff them
- if len(items) < 2 {
- return nil, ErrNotEnoughParameters
- }
- switch dt := items[0].(type) {
- case time.Duration:
- diff = dt
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsDuration(item); err != nil {
- return nil, err
- } else {
- diff = diff.(time.Duration) - itmVal
- }
- }
- case time.Time:
- diff = dt
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsDuration(item); err != nil {
- return nil, err
- } else {
- diff = diff.(time.Time).Add(-itmVal)
- }
- }
- case float64:
- diff = dt
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsFloat64(item); err != nil {
- return nil, err
- } else {
- diff = diff.(float64) - itmVal
- }
- }
- case int64:
- diff = dt
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsInt64(item); err != nil {
- return nil, err
- } else {
- diff = diff.(int64) - itmVal
- }
- }
- case int:
- // need explicit conversion for int
- if firstItmVal, err := IfaceAsInt64(dt); err != nil {
- return nil, err
- } else {
- diff = firstItmVal
- }
- for _, item := range items[1:] {
- if itmVal, err := IfaceAsInt64(item); err != nil {
- return nil, err
- } else {
- diff = diff.(int64) - itmVal
- }
- }
- default: // unsupported comparison
- return nil, fmt.Errorf("unsupported type")
- }
- return
-}
-
-// ReflectFieldMethodInterface parses intf attepting to return the field value or error otherwise
-// Supports "ExtraFields" where additional fields are dynamically inserted in map with field name: extraFieldsLabel
-func ReflectFieldMethodInterface(obj any, fldName string) (retIf any, err error) {
- v := reflect.ValueOf(obj)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- var field reflect.Value
- switch v.Kind() {
- case reflect.Struct:
- field = v.FieldByName(fldName)
- case reflect.Map:
- field = v.MapIndex(reflect.ValueOf(fldName))
- case reflect.Slice, reflect.Array:
- //convert fldName to int
- idx, err := strconv.Atoi(fldName)
- if err != nil {
- return nil, err
- }
- if idx >= v.Len() {
- return nil, fmt.Errorf("index out of range")
- }
- field = v.Index(idx)
- default:
- return nil, fmt.Errorf("unsupported field kind: %v", v.Kind())
- }
- if !field.IsValid() {
- // handle function with pointer
- v = reflect.ValueOf(obj)
- field = v.MethodByName(fldName)
- if !field.IsValid() {
- return nil, ErrNotFound
- } else {
- if field.Type().NumIn() != 0 {
- return nil, fmt.Errorf("invalid function called")
- }
- if field.Type().NumOut() > 2 {
- return nil, fmt.Errorf("invalid function called")
- }
- // the function have two parameters in return and check if the second is of type error
- if field.Type().NumOut() == 2 {
- errorInterface := reflect.TypeOf((*error)(nil)).Elem()
- if !field.Type().Out(1).Implements(errorInterface) {
- return nil, fmt.Errorf("invalid function called")
- }
- }
- fields := field.Call([]reflect.Value{})
- if len(fields) == 2 && !fields[1].IsNil() {
- return fields[0].Interface(), fields[1].Interface().(error)
- }
- return fields[0].Interface(), nil
- }
- }
- return field.Interface(), nil
-}
-
-
-
/*
-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 utils
-
-import (
- "regexp"
-)
-
-// Regexp Search/Replace, used for example for field formatting
-type ReSearchReplace struct {
- SearchRegexp *regexp.Regexp
- ReplaceTemplate string
- Matched bool
-}
-
-func (rsr *ReSearchReplace) Process(source string) string {
- if rsr.SearchRegexp == nil {
- return ""
- }
- res := []byte{}
- match := rsr.SearchRegexp.FindStringSubmatchIndex(source)
- if match == nil {
- return source // No match returns unaltered source, so we can play with national vs international dialing
- } else {
- rsr.Matched = true
- }
- res = rsr.SearchRegexp.ExpandString(res, rsr.ReplaceTemplate, source, match)
- return string(res)
-}
-
-
-
/*
-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 utils
-
-import (
- "reflect"
- "sync"
-)
-
-var (
- rpcParamsMap = make(map[string]*RpcParams)
- rpcParamsLock sync.RWMutex
-)
-
-type RpcParams struct {
- Object any
- InParam any
- OutParam any
-}
-
-func RegisterRpcParams(name string, obj any) {
- objType := reflect.TypeOf(obj)
- if name == "" {
- val := reflect.ValueOf(obj)
- name = objType.Name()
- if val.Kind() == reflect.Ptr {
- name = objType.Elem().Name()
- }
- }
- for i := 0; i < objType.NumMethod(); i++ {
- method := objType.Method(i)
- methodType := method.Type
- if methodType.NumIn() == 3 { // if it has three parameters (one is self and two are rpc params)
- out := methodType.In(2)
- if out.Kind() == reflect.Ptr {
- out = out.Elem()
- }
- rpcParamsLock.Lock()
- rpcParamsMap[name+"."+method.Name] = &RpcParams{
- Object: obj,
- InParam: reflect.New(methodType.In(1)).Interface(),
- OutParam: reflect.New(out).Interface(),
- }
- rpcParamsLock.Unlock()
- }
- }
-}
-
-func GetRpcParams(method string) (*RpcParams, error) {
- rpcParamsLock.Lock()
- x, found := rpcParamsMap[method]
- rpcParamsLock.Unlock()
- if !found {
- return nil, ErrNotFound
- }
- return x, nil
-}
-
-
-
/*
-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 utils
-
-import (
- "fmt"
- "regexp"
- "strings"
-)
-
-var (
- spltRgxp = regexp.MustCompile(`:s\/`)
- rulesRgxp = regexp.MustCompile(`(?:(.+[^\\])\/(.*[^\\])*\/){1,}`)
-)
-
-func NewRSRField(fldStr string) (fld *RSRField, err error) {
- if len(fldStr) == 0 {
- return nil, nil
- }
- rsrField := &RSRField{Rules: fldStr}
- var filters []*RSRFilter
- if strings.HasSuffix(fldStr, FILTER_VAL_END) { // Has filter, populate the var
- fltrStart := strings.LastIndex(fldStr, FILTER_VAL_START)
- if fltrStart < 1 {
- return nil, fmt.Errorf("Invalid FilterStartValue in string: %s", fldStr)
- }
- fltrVal := fldStr[fltrStart+1 : len(fldStr)-1]
- filters, err = ParseRSRFilters(fltrVal, MetaPipe)
- if err != nil {
- return nil, fmt.Errorf("Invalid FilterValue in string: %s, err: %s", fltrVal, err.Error())
- }
- fldStr = fldStr[:fltrStart] // Take the filter part out before compiling further
-
- }
- if idxConverters := strings.Index(fldStr, "{*"); idxConverters != -1 { // converters in the string
- if !strings.HasSuffix(fldStr, "}") {
- return nil,
- fmt.Errorf("Invalid converter value in string: %s, err: invalid converter terminator",
- fldStr)
- }
- convertersStr := fldStr[idxConverters+1 : len(fldStr)-1] // strip also {}
- convsSplt := strings.Split(convertersStr, INFIELD_SEP)
- rsrField.converters = make([]DataConverter, len(convsSplt))
- for i, convStr := range convsSplt {
- if conv, err := NewDataConverter(convStr); err != nil {
- return nil,
- fmt.Errorf("Invalid converter value in string: %s, err: %s",
- convStr, err.Error())
- } else {
- rsrField.converters[i] = conv
- }
- }
- fldStr = fldStr[:idxConverters]
- }
- if strings.HasPrefix(fldStr, STATIC_VALUE_PREFIX) { // Special case when RSR is defined as static header/value
- var staticHdr, staticVal string
- if splt := strings.Split(fldStr, STATIC_HDRVAL_SEP); len(splt) == 2 { // Using / as separator since ':' is often use in date/time fields
- staticHdr, staticVal = splt[0][1:], splt[1] // Strip the / suffix
- staticVal = strings.TrimSuffix(staticVal, "/") // If value ends with /, strip it since it is a part of the definition syntax
- } else if len(splt) > 2 {
- return nil, fmt.Errorf("Invalid RSRField string: %s", fldStr)
- } else {
- staticHdr, staticVal = splt[0][1:], splt[0][1:] // If no split, header will remain as original, value as header without the prefix
- }
- rsrField.Id = staticHdr
- rsrField.staticValue = staticVal
- rsrField.filters = filters
- return rsrField, nil
- }
- if !strings.HasPrefix(fldStr, REGEXP_PREFIX) {
- rsrField.Id = fldStr
- rsrField.filters = filters
- return rsrField, nil
- }
- spltRules := spltRgxp.Split(fldStr, -1)
- if len(spltRules) < 2 {
- return nil, fmt.Errorf("Invalid Split of Search&Replace field rule. %s", fldStr)
- }
- rsrField.Id = spltRules[0][1:]
- rsrField.filters = filters // Original id in form ~hdr_name
- for _, ruleStr := range spltRules[1:] { // :s/ already removed through split
- allMatches := rulesRgxp.FindStringSubmatch(ruleStr)
- if len(allMatches) != 3 {
- return nil, fmt.Errorf("Not enough members in Search&Replace, ruleStr: %s, matches: %v, ", ruleStr, allMatches)
- }
- if srRegexp, err := regexp.Compile(allMatches[1]); err != nil {
- return nil, fmt.Errorf("Invalid Search&Replace subfield rule: %s", allMatches[1])
- } else {
- rsrField.RSRules = append(rsrField.RSRules, &ReSearchReplace{SearchRegexp: srRegexp, ReplaceTemplate: allMatches[2]})
- }
- }
- return rsrField, nil
-}
-
-func NewRSRFieldMustCompile(fldStr string) (rsrFld *RSRField) {
- var err error
- if rsrFld, err = NewRSRField(fldStr); err != nil {
- return nil
- }
- return
-}
-
-type RSRField struct {
- Id string // Identifier
- Rules string // Rules container holding the string rules to be able to restore it after DB
- staticValue string // If defined, enforces parsing always to this value
- RSRules []*ReSearchReplace // Rules to use when processing field value
- filters []*RSRFilter // The value to compare when used as filter
- converters DataConverters // set of converters to apply on output
-}
-
-// IsCompiled finds out whether this RSRField was already parsed or RAW state
-func (rsrf *RSRField) IsCompiled() bool {
- return rsrf.staticValue != "" ||
- rsrf.RSRules != nil ||
- rsrf.filters != nil ||
- rsrf.converters != nil
-}
-
-// Compile parses Rules string and repopulates other fields
-func (rsrf *RSRField) Compile() error {
- if newRSRFld, err := NewRSRField(rsrf.Rules); err != nil {
- return err
- } else if newRSRFld != nil {
- rsrf.staticValue = newRSRFld.staticValue
- rsrf.RSRules = newRSRFld.RSRules
- rsrf.filters = newRSRFld.filters
- }
- return nil
-}
-
-// IsStatic detects if a RSRField is a static value
-func (rsrf *RSRField) IsStatic() bool {
- return len(rsrf.staticValue) != 0
-}
-
-// RegexpMatched will investigate whether we had a regexp match through the rules
-func (rsrf *RSRField) RegexpMatched() bool {
- for _, rsrule := range rsrf.RSRules {
- if rsrule.Matched {
- return true
- }
- }
- return false
-}
-
-// parseValue the field value from a string
-func (rsrf *RSRField) parseValue(value string) string {
- if len(rsrf.staticValue) != 0 { // Enforce parsing of static values
- return rsrf.staticValue
- }
- for _, rsRule := range rsrf.RSRules {
- if rsRule != nil {
- value = rsRule.Process(value)
- }
- }
- return value
-}
-
-func (rsrf *RSRField) filtersPassing(value string) bool {
- for _, fltr := range rsrf.filters {
- if !fltr.Pass(value) {
- return false
- }
- }
- return true
-}
-
-// Parse will parse the value out considering converters and filters
-func (rsrf *RSRField) Parse(value any) (out string, err error) {
- out = rsrf.parseValue(IfaceAsString(value))
- if out, err = rsrf.converters.ConvertString(out); err != nil {
- return
- }
- if !rsrf.filtersPassing(out) {
- return "", ErrFilterNotPassingNoCaps
- }
- return
-}
-
-// NewRSRFilter instantiates a new RSRFilter, setting it's properties
-func NewRSRFilter(fltrVal string) (rsrFltr *RSRFilter, err error) {
- rsrFltr = new(RSRFilter)
- if fltrVal == "" {
- return rsrFltr, nil
- }
- if fltrVal[:1] == NegativePrefix {
- rsrFltr.negative = true
- fltrVal = fltrVal[1:]
- if fltrVal == "" {
- return rsrFltr, nil
- }
- }
- rsrFltr.filterRule = fltrVal
- if fltrVal[:1] == REGEXP_PREFIX {
- if rsrFltr.fltrRgxp, err = regexp.Compile(fltrVal[1:]); err != nil {
- return nil, err
- }
- }
- return rsrFltr, nil
-}
-
-// NewRSRFilterMustCompile is used mostly in tests
-func NewRSRFilterMustCompile(fltrVal string) (rsrFltr *RSRFilter) {
- var err error
- if rsrFltr, err = NewRSRFilter(fltrVal); err != nil {
- panic(fmt.Sprintf("parsing <%s>, err: %s", fltrVal, err.Error()))
- }
- return
-}
-
-// One filter rule
-type RSRFilter struct {
- filterRule string // Value in raw format
- fltrRgxp *regexp.Regexp
- negative bool // Rule should not match
-}
-
-func (rsrFltr *RSRFilter) FilterRule() string {
- return rsrFltr.filterRule
-}
-
-func (rsrFltr *RSRFilter) Pass(val string) bool {
- if rsrFltr.filterRule == "" {
- return !rsrFltr.negative
- }
- if rsrFltr.filterRule[:1] == REGEXP_PREFIX {
- return rsrFltr.fltrRgxp.MatchString(val) != rsrFltr.negative
- }
- if rsrFltr.filterRule == "^$" { // Special case to test empty value
- return len(val) == 0 != rsrFltr.negative
- }
- if rsrFltr.filterRule[:1] == MatchStartPrefix {
- if rsrFltr.filterRule[len(rsrFltr.filterRule)-1:] == MatchEndPrefix { // starts with ^ and ends with $, exact match
- return val == rsrFltr.filterRule[1:len(rsrFltr.filterRule)-1] != rsrFltr.negative
- }
- return strings.HasPrefix(val, rsrFltr.filterRule[1:]) != rsrFltr.negative
- }
- lastIdx := len(rsrFltr.filterRule) - 1
- if rsrFltr.filterRule[lastIdx:] == MatchEndPrefix {
- return strings.HasSuffix(val, rsrFltr.filterRule[:lastIdx]) != rsrFltr.negative
- }
- if len(rsrFltr.filterRule) > 2 && rsrFltr.filterRule[:2] == MatchGreaterThanOrEqual {
- gt, err := GreaterThan(StringToInterface(val),
- StringToInterface(rsrFltr.filterRule[2:]), true)
- if err != nil {
- Logger.Warning(fmt.Sprintf("<RSRFilter> rule: <%s>, err: <%s>", rsrFltr.filterRule, err.Error()))
- return false
- }
- return gt != rsrFltr.negative
- }
-
- if len(rsrFltr.filterRule) > 2 && rsrFltr.filterRule[:2] == MatchLessThanOrEqual {
- gt, err := GreaterThan(StringToInterface(rsrFltr.filterRule[2:]), // compare the rule with the val
- StringToInterface(val),
- true)
- if err != nil {
- Logger.Warning(fmt.Sprintf("<RSRFilter> rule: <%s>, err: <%s>", rsrFltr.filterRule, err.Error()))
- return false
- }
- return gt != rsrFltr.negative
- }
-
- if rsrFltr.filterRule[:1] == MatchGreaterThan {
- gt, err := GreaterThan(StringToInterface(val),
- StringToInterface(rsrFltr.filterRule[1:]), false)
- if err != nil {
- Logger.Warning(fmt.Sprintf("<RSRFilter> rule: <%s>, err: <%s>", rsrFltr.filterRule, err.Error()))
- return false
- }
- return gt != rsrFltr.negative
- }
-
- if rsrFltr.filterRule[:1] == MatchLessThan {
- gt, err := GreaterThan(StringToInterface(rsrFltr.filterRule[1:]), // compare the rule with the val
- StringToInterface(val),
- false)
- if err != nil {
- Logger.Warning(fmt.Sprintf("<RSRFilter> rule: <%s>, err: <%s>", rsrFltr.filterRule, err.Error()))
- return false
- }
- return gt != rsrFltr.negative
- }
- return strings.Contains(val, rsrFltr.filterRule) != rsrFltr.negative // default is string index
-}
-
-func ParseRSRFilters(fldsStr, sep string) (RSRFilters, error) {
- if fldsStr == "" {
- return nil, nil
- }
- fltrSplt := strings.Split(fldsStr, sep)
- return ParseRSRFiltersFromSlice(fltrSplt)
-}
-
-func ParseRSRFiltersFromSlice(fltrStrs []string) (RSRFilters, error) {
- rsrFltrs := make(RSRFilters, len(fltrStrs))
- for i, rlStr := range fltrStrs {
- if rsrFltr, err := NewRSRFilter(rlStr); err != nil {
- return nil, err
- } else if rsrFltr == nil {
- return nil, fmt.Errorf("Empty RSRFilter in rule: %s", rlStr)
- } else {
- rsrFltrs[i] = rsrFltr
- }
- }
- return rsrFltrs, nil
-}
-
-type RSRFilters []*RSRFilter
-
-func (fltrs RSRFilters) FilterRules() (rls string) {
- for _, fltr := range fltrs {
- rls += fltr.FilterRule()
- }
- return
-}
-
-// @all: specifies whether all filters should match or at least one
-func (fltrs RSRFilters) Pass(val string, allMustMatch bool) (matched bool) {
- if len(fltrs) == 0 {
- return true
- }
- for _, fltr := range fltrs {
- matched = fltr.Pass(val)
- if allMustMatch {
- if !matched {
- return
- }
- } else if matched {
- return
- }
- }
- return
-}
-
-func ParseRSRFieldsFromSlice(flds []string) (RSRFields, error) {
- if len(flds) == 0 {
- return nil, nil
- }
- rsrFields := make(RSRFields, len(flds))
- for idx, ruleStr := range flds {
- if rsrField, err := NewRSRField(ruleStr); err != nil {
- return nil, err
- } else if rsrField == nil {
- return nil, fmt.Errorf("Empty RSRField in rule: %s", ruleStr)
- } else {
- rsrFields[idx] = rsrField
- }
- }
- return rsrFields, nil
-
-}
-
-// Parses list of RSRFields, used for example as multiple filters in derived charging
-func ParseRSRFields(fldsStr, sep string) (RSRFields, error) {
- //rsrRlsPattern := regexp.MustCompile(`^(~\w+:s/.+/.*/)|(\^.+(/.+/)?)(;(~\w+:s/.+/.*/)|(\^.+(/.+/)?))*$`) //ToDo:Fix here rule able to confirm the content
- if len(fldsStr) == 0 {
- return nil, nil
- }
- rulesSplt := strings.Split(fldsStr, sep)
- return ParseRSRFieldsFromSlice(rulesSplt)
-
-}
-
-func ParseRSRFieldsMustCompile(fldsStr, sep string) RSRFields {
- if flds, err := ParseRSRFields(fldsStr, sep); err != nil {
- return nil
- } else {
- return flds
- }
-}
-
-type RSRFields []*RSRField
-
-// Return first Id of the rsrFields, used in cdre
-func (flds RSRFields) Id() string {
- if len(flds) == 0 {
- return ""
- }
- return flds[0].Id
-}
-
-func (flds RSRFields) Compile() (err error) {
- for _, rsrFld := range flds {
- if err = rsrFld.Compile(); err != nil {
- break
- }
- }
- return
-}
-
-
-
/*
-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 utils
-
-import (
- "bytes"
- "crypto/tls"
- "crypto/x509"
- "encoding/gob"
- "fmt"
- "io"
- "log"
- "net"
- "net/http"
- "net/http/pprof"
- "net/rpc"
- "net/url"
- "os"
- "strings"
- "sync"
- "time"
-
- "github.com/cgrates/birpc"
- "github.com/cgrates/birpc/jsonrpc"
- "golang.org/x/net/websocket"
-)
-
-func init() {
- gob.Register(map[string]any{})
- gob.Register([]any{})
- gob.Register(time.Duration(0))
- gob.Register(time.Time{})
- gob.Register(url.Values{})
-}
-func NewServer() (s *Server) {
- s = new(Server)
- s.birpcSrv = birpc.NewBirpcServer()
- s.httpMux = http.NewServeMux()
- s.httpsMux = http.NewServeMux()
- s.stopbiRPCServer = make(chan struct{}, 1)
- return s
-}
-
-type Server struct {
- sync.RWMutex
- rpcEnabled bool
- httpEnabled bool
- birpcSrv *birpc.BirpcServer
- stopbiRPCServer chan struct{} // used in order to fully stop the biRPC
- httpsMux *http.ServeMux
- httpMux *http.ServeMux
- isDispatched bool
-}
-
-func (s *Server) SetDispatched() {
- s.isDispatched = true
-}
-
-func (s *Server) RpcRegister(rcvr any) {
- rpc.Register(rcvr)
- s.Lock()
- s.rpcEnabled = true
- s.Unlock()
-}
-
-func (s *Server) RpcRegisterName(name string, rcvr any) {
- rpc.RegisterName(name, rcvr)
- s.Lock()
- s.rpcEnabled = true
- s.Unlock()
-}
-
-func (s *Server) RegisterHttpFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
- if s.httpMux != nil {
- s.httpMux.HandleFunc(pattern, handler)
- }
- if s.httpsMux != nil {
- s.httpsMux.HandleFunc(pattern, handler)
- }
- s.Lock()
- s.httpEnabled = true
- s.Unlock()
-}
-
-func (s *Server) RegisterHttpHandler(pattern string, handler http.Handler) {
- if s.httpMux != nil {
- s.httpMux.Handle(pattern, handler)
- }
- if s.httpsMux != nil {
- s.httpsMux.Handle(pattern, handler)
- }
- s.Lock()
- s.httpEnabled = true
- s.Unlock()
-}
-
-// Registers a new BiJsonRpc name
-func (s *Server) BiRPCRegisterName(name string, rcv any) {
- s.birpcSrv.RegisterName(name, rcv)
-}
-
-func (s *Server) BiRPCUnregisterName(name string) {
- s.birpcSrv.UnregisterName(name)
-}
-
-func (s *Server) ServeJSON(addr string, exitChan chan bool) {
- s.RLock()
- enabled := s.rpcEnabled
- s.RUnlock()
- if !enabled {
- return
- }
-
- lJSON, e := net.Listen(TCP, addr)
- if e != nil {
- log.Println("ServeJSON listen error:", e)
- exitChan <- true
- return
- }
- Logger.Info(fmt.Sprintf("Starting CGRateS JSON server at <%s>.", addr))
- errCnt := 0
- var lastErrorTime time.Time
- for {
- conn, err := lJSON.Accept()
- if err != nil {
- Logger.Err(fmt.Sprintf("<CGRServer> JSON accept error: <%s>", err.Error()))
- now := time.Now()
- if now.Sub(lastErrorTime) > time.Duration(5*time.Second) {
- errCnt = 0 // reset error count if last error was more than 5 seconds ago
- }
- lastErrorTime = time.Now()
- errCnt++
- if errCnt > 50 { // Too many errors in short interval, network buffer failure most probably
- break
- }
- continue
- }
- //utils.Logger.Info(fmt.Sprintf("<CGRServer> New incoming connection: %v", conn.RemoteAddr()))
- if s.isDispatched {
- go rpc.ServeCodec(NewCustomJSONServerCodec(conn))
- } else {
- go rpc.ServeCodec(NewConcReqsServerCodec(conn))
- }
-
- }
-
-}
-
-func (s *Server) ServeGOB(addr string, exitChan chan bool) {
- s.RLock()
- enabled := s.rpcEnabled
- s.RUnlock()
- if !enabled {
- return
- }
- lGOB, e := net.Listen(TCP, addr)
- if e != nil {
- log.Println("ServeGOB listen error:", e)
- exitChan <- true
- return
- }
- Logger.Info(fmt.Sprintf("Starting CGRateS GOB server at <%s>.", addr))
- errCnt := 0
- var lastErrorTime time.Time
- for {
- conn, err := lGOB.Accept()
- if err != nil {
- Logger.Err(fmt.Sprintf("<CGRServer> GOB accept error: <%s>", err.Error()))
- now := time.Now()
- if now.Sub(lastErrorTime) > time.Duration(5*time.Second) {
- errCnt = 0 // reset error count if last error was more than 5 seconds ago
- }
- lastErrorTime = time.Now()
- errCnt += 1
- if errCnt > 50 { // Too many errors in short interval, network buffer failure most probably
- break
- }
- continue
- }
-
- go rpc.ServeCodec(NewConcReqsGobServerCodec(conn))
- }
-}
-
-func handleRequest(w http.ResponseWriter, r *http.Request) {
- defer r.Body.Close()
- w.Header().Set("Content-Type", "application/json")
- res := NewRPCRequest(r.Body).Call()
- io.Copy(w, res)
-}
-
-func registerProfiler(addr string, mux *http.ServeMux) {
- mux.HandleFunc(addr, pprof.Index)
- mux.HandleFunc(addr+"cmdline", pprof.Cmdline)
- mux.HandleFunc(addr+"profile", pprof.Profile)
- mux.HandleFunc(addr+"symbol", pprof.Symbol)
- mux.HandleFunc(addr+"trace", pprof.Trace)
- mux.Handle(addr+"goroutine", pprof.Handler("goroutine"))
- mux.Handle(addr+"heap", pprof.Handler("heap"))
- mux.Handle(addr+"threadcreate", pprof.Handler("threadcreate"))
- mux.Handle(addr+"block", pprof.Handler("block"))
- mux.Handle(addr+"allocs", pprof.Handler("allocs"))
- mux.Handle(addr+"mutex", pprof.Handler("mutex"))
-}
-
-func (s *Server) RegisterProfiler(addr string) {
- if addr[len(addr)-1] != '/' {
- addr = addr + "/"
- }
- registerProfiler(addr, s.httpMux)
- registerProfiler(addr, s.httpsMux)
-}
-
-func (s *Server) ServeHTTP(addr string, jsonRPCURL string, wsRPCURL string,
- useBasicAuth bool, userList map[string]string, exitChan chan bool) {
- s.RLock()
- enabled := s.rpcEnabled
- s.RUnlock()
- if !enabled {
- return
- }
- // s.httpMux = http.NewServeMux()
- if enabled && jsonRPCURL != "" {
- s.Lock()
- s.httpEnabled = true
- s.Unlock()
-
- Logger.Info("<HTTP> enabling handler for JSON-RPC")
- if useBasicAuth {
- s.httpMux.HandleFunc(jsonRPCURL, use(handleRequest, basicAuth(userList)))
- } else {
- s.httpMux.HandleFunc(jsonRPCURL, handleRequest)
- }
- }
- if enabled && wsRPCURL != "" {
- s.Lock()
- s.httpEnabled = true
- s.Unlock()
- Logger.Info("<HTTP> enabling handler for WebSocket connections")
- wsHandler := websocket.Handler(func(ws *websocket.Conn) {
- if s.isDispatched {
- rpc.ServeCodec(NewCustomJSONServerCodec(ws))
- } else {
- rpc.ServeCodec(NewConcReqsServerCodec(ws))
- }
- })
- if useBasicAuth {
- s.httpMux.HandleFunc(wsRPCURL, use(func(w http.ResponseWriter, r *http.Request) {
- wsHandler.ServeHTTP(w, r)
- }, basicAuth(userList)))
- } else {
- s.httpMux.Handle(wsRPCURL, wsHandler)
- }
- }
- if !s.httpEnabled {
- return
- }
- if useBasicAuth {
- Logger.Info("<HTTP> enabling basic auth")
- }
- Logger.Info(fmt.Sprintf("<HTTP> start listening at <%s>", addr))
- if err := http.ListenAndServe(addr, s.httpMux); err != nil {
- log.Printf("<HTTP>Error: %s when listening ", err)
- }
- exitChan <- true
-}
-
-// ServeBiJSON create a gorutine to listen and serve as BiRPC server
-func (s *Server) ServeBiJSON(addr string, onConn, onDis func(birpc.ClientConnector)) (err error) {
- s.RLock()
- isNil := s.birpcSrv == nil
- s.RUnlock()
- if isNil {
- return fmt.Errorf("BiRPCServer should not be nil")
- }
- var lBiJSON net.Listener
- lBiJSON, err = net.Listen(TCP, addr)
- if err != nil {
- log.Println("ServeBiJSON listen error:", err)
- return
- }
- s.birpcSrv.OnConnect(onConn)
- s.birpcSrv.OnDisconnect(onDis)
- Logger.Info(fmt.Sprintf("Starting CGRateS BiJSON server at <%s>", addr))
- go func(l net.Listener) {
- for {
- conn, err := l.Accept()
- if err != nil {
- if strings.Contains(err.Error(), "use of closed network connection") { // if closed by us do not log
- return
- }
- s.stopbiRPCServer <- struct{}{}
- log.Fatal(err)
- return // stop if we get Accept error
- }
- go s.birpcSrv.ServeCodec(jsonrpc.NewJSONBirpcCodec(conn))
- }
- }(lBiJSON)
- <-s.stopbiRPCServer // wait until server is stoped to close the listener
- lBiJSON.Close()
- return
-}
-
-// StopBiRPC stops the go rutine create with ServeBiJSON
-func (s *Server) StopBiRPC() {
- s.stopbiRPCServer <- struct{}{}
-}
-
-// rpcRequest represents a RPC request.
-// rpcRequest implements the io.ReadWriteCloser interface.
-type rpcRequest struct {
- r io.Reader // holds the JSON formated RPC request
- rw io.ReadWriter // holds the JSON formated RPC response
- done chan bool // signals then end of the RPC request
-}
-
-// NewRPCRequest returns a new rpcRequest.
-func NewRPCRequest(r io.Reader) *rpcRequest {
- var buf bytes.Buffer
- done := make(chan bool)
- return &rpcRequest{r, &buf, done}
-}
-
-func (r *rpcRequest) Read(p []byte) (n int, err error) {
- return r.r.Read(p)
-}
-
-func (r *rpcRequest) Write(p []byte) (n int, err error) {
- n, err = r.rw.Write(p)
- r.done <- true
- return
-}
-
-func (r *rpcRequest) Close() error {
- //r.done <- true // seem to be called sometimes before the write command finishes!
- return nil
-}
-
-// Call invokes the RPC request, waits for it to complete, and returns the results.
-func (r *rpcRequest) Call() io.Reader {
- go rpc.ServeCodec(NewConcReqsServerCodec(r))
- <-r.done
- return r.rw
-}
-
-func loadTLSConfig(serverCrt, serverKey, caCert string, serverPolicy int,
- serverName string) (config tls.Config, err error) {
- cert, err := tls.LoadX509KeyPair(serverCrt, serverKey)
- if err != nil {
- log.Fatalf("Error: %s when load server keys", err)
- }
- rootCAs, err := x509.SystemCertPool()
- if err != nil {
- log.Fatalf("Error: %s when load SystemCertPool", err)
- return
- }
- if rootCAs == nil {
- rootCAs = x509.NewCertPool()
- }
-
- if caCert != "" {
- ca, err := os.ReadFile(caCert)
- if err != nil {
- log.Fatalf("Error: %s when read CA", err)
- return config, err
- }
-
- if ok := rootCAs.AppendCertsFromPEM(ca); !ok {
- log.Fatalf("Cannot append certificate authority")
- return config, err
- }
- }
-
- config = tls.Config{
- Certificates: []tls.Certificate{cert},
- ClientAuth: tls.ClientAuthType(serverPolicy),
- ClientCAs: rootCAs,
- }
- if serverName != "" {
- config.ServerName = serverName
- }
- return
-}
-
-func (s *Server) ServeGOBTLS(addr, serverCrt, serverKey, caCert string,
- serverPolicy int, serverName string, exitChan chan bool) {
- s.RLock()
- enabled := s.rpcEnabled
- s.RUnlock()
- if !enabled {
- return
- }
- config, err := loadTLSConfig(serverCrt, serverKey, caCert, serverPolicy, serverName)
- if err != nil {
- return
- }
- listener, err := tls.Listen(TCP, addr, &config)
- if err != nil {
- log.Printf("Error: %s when listening", err)
- exitChan <- true
- return
- }
-
- Logger.Info(fmt.Sprintf("Starting CGRateS GOB TLS server at <%s>.", addr))
- errCnt := 0
- var lastErrorTime time.Time
- for {
- conn, err := listener.Accept()
- defer conn.Close()
- if err != nil {
- Logger.Err(fmt.Sprintf("<CGRServer> TLS accept error: <%s>", err.Error()))
- now := time.Now()
- if now.Sub(lastErrorTime) > time.Duration(5*time.Second) {
- errCnt = 0 // reset error count if last error was more than 5 seconds ago
- }
- lastErrorTime = time.Now()
- errCnt++
- if errCnt > 50 { // Too many errors in short interval, network buffer failure most probably
- break
- }
- continue
- }
- //utils.Logger.Info(fmt.Sprintf("<CGRServer> New incoming connection: %v", conn.RemoteAddr()))
- go rpc.ServeCodec(NewConcReqsGobServerCodec(conn))
- }
-}
-
-func (s *Server) ServeJSONTLS(addr, serverCrt, serverKey, caCert string,
- serverPolicy int, serverName string, exitChan chan bool) {
- s.RLock()
- enabled := s.rpcEnabled
- s.RUnlock()
- if !enabled {
- return
- }
- config, err := loadTLSConfig(serverCrt, serverKey, caCert, serverPolicy, serverName)
- if err != nil {
- return
- }
- listener, err := tls.Listen(TCP, addr, &config)
- if err != nil {
- log.Printf("Error: %s when listening", err)
- exitChan <- true
- return
- }
- Logger.Info(fmt.Sprintf("Starting CGRateS JSON TLS server at <%s>.", addr))
- errCnt := 0
- var lastErrorTime time.Time
- for {
- conn, err := listener.Accept()
- defer conn.Close()
- if err != nil {
- Logger.Err(fmt.Sprintf("<CGRServer> TLS accept error: <%s>", err.Error()))
- now := time.Now()
- if now.Sub(lastErrorTime) > time.Duration(5*time.Second) {
- errCnt = 0 // reset error count if last error was more than 5 seconds ago
- }
- lastErrorTime = time.Now()
- errCnt++
- if errCnt > 50 { // Too many errors in short interval, network buffer failure most probably
- break
- }
- continue
- }
- if s.isDispatched {
- go rpc.ServeCodec(NewCustomJSONServerCodec(conn))
- } else {
- go rpc.ServeCodec(NewConcReqsServerCodec(conn))
- }
- }
-}
-
-func (s *Server) ServeHTTPTLS(addr, serverCrt, serverKey, caCert string, serverPolicy int,
- serverName string, jsonRPCURL string, wsRPCURL string,
- useBasicAuth bool, userList map[string]string, exitChan chan bool) {
- s.RLock()
- enabled := s.rpcEnabled
- s.RUnlock()
- if !enabled {
- return
- }
- // s.httpsMux = http.NewServeMux()
- if enabled && jsonRPCURL != "" {
- s.Lock()
- s.httpEnabled = true
- s.Unlock()
- Logger.Info("<HTTPS> enabling handler for JSON-RPC")
- if useBasicAuth {
- s.httpsMux.HandleFunc(jsonRPCURL, use(handleRequest, basicAuth(userList)))
- } else {
- s.httpsMux.HandleFunc(jsonRPCURL, handleRequest)
- }
- }
- if enabled && wsRPCURL != "" {
- s.Lock()
- s.httpEnabled = true
- s.Unlock()
- Logger.Info("<HTTPS> enabling handler for WebSocket connections")
- wsHandler := websocket.Handler(func(ws *websocket.Conn) {
- if s.isDispatched {
- rpc.ServeCodec(NewCustomJSONServerCodec(ws))
- } else {
- rpc.ServeCodec(NewConcReqsServerCodec(ws))
- }
- })
- if useBasicAuth {
- s.httpsMux.HandleFunc(wsRPCURL, use(func(w http.ResponseWriter, r *http.Request) {
- wsHandler.ServeHTTP(w, r)
- }, basicAuth(userList)))
- } else {
- s.httpsMux.Handle(wsRPCURL, wsHandler)
- }
- }
- if !s.httpEnabled {
- return
- }
- if useBasicAuth {
- Logger.Info("<HTTPS> enabling basic auth")
- }
- config, err := loadTLSConfig(serverCrt, serverKey, caCert, serverPolicy, serverName)
- if err != nil {
- return
- }
- httpSrv := http.Server{
- Addr: addr,
- Handler: s.httpsMux,
- TLSConfig: &config,
- }
- Logger.Info(fmt.Sprintf("<HTTPS> start listening at <%s>", addr))
- if err := httpSrv.ListenAndServeTLS(serverCrt, serverKey); err != nil {
- log.Printf("<HTTPS>Error: %s when listening ", err)
- }
- exitChan <- true
-}
-
-
-
/*
-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 utils
-
-import "sort"
-
-// NewStringSet returns a new StringSet
-func NewStringSet(dataSlice []string) (s StringSet) {
- s = make(StringSet)
- s.AddSlice(dataSlice)
- return s
-}
-
-// StringSet will manage data within a set
-type StringSet map[string]struct{}
-
-// Add adds a key in set
-func (s StringSet) Add(val string) {
- s[val] = struct{}{}
-}
-
-// Remove removes a key from set
-func (s StringSet) Remove(val string) {
- delete(s, val)
-}
-
-// Has returns if the key is in set
-func (s StringSet) Has(val string) bool {
- _, has := s[val]
- return has
-}
-
-// AddSlice adds all the element of a slice
-func (s StringSet) AddSlice(dataSlice []string) {
- for _, val := range dataSlice {
- s.Add(val)
- }
-}
-
-// AsSlice returns the keys as string slice
-func (s StringSet) AsSlice() []string {
- result := make([]string, len(s))
- i := 0
- for k := range s {
- result[i] = k
- i++
- }
- return result
-}
-
-// AsOrderedSlice returns the keys as ordered string slice
-func (s StringSet) AsOrderedSlice() (ss []string) {
- ss = s.AsSlice()
- sort.Strings(ss)
- return
-}
-
-// Sha1 returns the Sha1 on top of ordered slice
-func (s StringSet) Sha1() string {
- return Sha1(s.AsOrderedSlice()...)
-}
-
-// Size returns the size of the set
-func (s StringSet) Size() int {
- return len(s)
-}
-
-// Intersect removes all key s2 do not have
-func (s StringSet) Intersect(s2 StringSet) {
- for k := range s {
- if !s2.Has(k) {
- s.Remove(k)
- }
- }
-}
-
-
-
/*
-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 utils
-
-import (
- "sort"
- "strings"
-)
-
-// Binary string search in slice
-func IsSliceMember(ss []string, s string) bool {
- sort.Strings(ss)
- return SliceHasMember(ss, s)
-}
-
-// SliceHasMember searches within a *sorted* slice
-// useful to search in shared vars (no slice sort)
-func SliceHasMember(ss []string, s string) bool {
- i := sort.SearchStrings(ss, s)
- return i < len(ss) && ss[i] == s
-}
-
-func SliceWithoutMember(ss []string, s string) []string {
- sort.Strings(ss)
- if i := sort.SearchStrings(ss, s); i < len(ss) && ss[i] == s {
- ss[i], ss = ss[len(ss)-1], ss[:len(ss)-1]
- }
- return ss
-}
-
-// Iterates over slice members and returns true if one starts with prefix
-func SliceMemberHasPrefix(ss []string, prfx string) bool {
- for _, mbr := range ss {
- if strings.HasPrefix(mbr, prfx) {
- return true
- }
- }
- return false
-}
-
-func Avg(values []float64) float64 {
- if len(values) == 0 {
- return 0.0
- }
- var sum float64
- for _, val := range values {
- sum += val
- }
- return sum / float64(len(values))
-}
-
-func AvgNegative(values []float64) float64 {
- if len(values) == 0 {
- return -1 // return -1 if no data
- }
- return Avg(values)
-}
-
-func PrefixSliceItems(slc []string, prfx string) (out []string) {
- out = make([]string, len(slc))
- for i, itm := range slc {
- out[i] = prfx + itm
- }
- return
-}
-
-// StripSlicePrefix will strip a number of items from the beginning of the slice
-func StripSlicePrefix(slc []string, nrItems int) []string {
- if len(slc) < nrItems {
- return []string{}
- }
- return slc[nrItems:]
-}
-
-// SliceStringToIface converts slice of strings into a slice of interfaces
-func SliceStringToIface(slc []string) (ifc []any) {
- ifc = make([]any, len(slc))
- for i, itm := range slc {
- ifc[i] = itm
- }
- return
-}
-
-// Float64SliceHasMember searches within a *sorted* slice
-// useful to search in shared vars (no slice sort)
-func Float64SliceHasMember(ss []float64, s float64) bool {
- i := sort.SearchFloat64s(ss, s)
- return i < len(ss) && ss[i] == s
-}
-
-// HasPrefixSlice iterates over slice members and returns true if one the element has that prefix
-func HasPrefixSlice(prfxs []string, el string) bool {
- for _, prfx := range prfxs {
- if strings.HasPrefix(el, prfx) {
- return true
- }
- }
- return false
-}
-
-
-
/*
-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 utils
-
-import (
- "errors"
- "fmt"
- "reflect"
- "strconv"
- "strings"
-)
-
-func fieldByIndexIsEmpty(v reflect.Value, index []int) bool {
- if len(index) == 1 {
- return valueIsEmpty(v.Field(index[0]))
- }
- for i, x := range index {
- if i > 0 {
- if v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct {
- if v.IsNil() {
- return true
- }
- v = v.Elem()
- }
- }
- v = v.Field(x)
- }
- return valueIsEmpty(v)
-}
-
-func valueIsEmpty(fld reflect.Value) bool {
- if fld.Kind() == reflect.String && fld.CanSet() {
- fld.SetString(strings.TrimSpace(fld.String()))
- }
- return (fld.Kind() == reflect.String && fld.String() == EmptyString) ||
- ((fld.Kind() == reflect.Slice || fld.Kind() == reflect.Map) && fld.Len() == 0) ||
- (fld.Kind() == reflect.Int && fld.Int() == 0)
-}
-
-// Detects missing field values based on mandatory field names, s should be a pointer to a struct
-func MissingStructFields(s any, mandatories []string) []string {
- missing := []string{}
- sValue := reflect.ValueOf(s).Elem()
- sType := sValue.Type()
- for _, fieldName := range mandatories {
- fldStr, ok := sType.FieldByName(fieldName)
- if !ok || fieldByIndexIsEmpty(sValue, fldStr.Index) {
- missing = append(missing, fieldName)
- }
- }
- return missing
-}
-
-// Detects nonempty struct fields, s should be a pointer to a struct
-// Useful to not overwrite db fields with non defined params in api
-func NonemptyStructFields(s any) map[string]any {
- fields := make(map[string]any)
- for i := 0; i < reflect.ValueOf(s).Elem().NumField(); i++ {
- fld := reflect.ValueOf(s).Elem().Field(i)
- switch fld.Kind() {
- case reflect.Bool:
- fields[reflect.TypeOf(s).Elem().Field(i).Name] = fld.Bool()
- case reflect.Int:
- fieldVal := fld.Int()
- if fieldVal != 0 {
- fields[reflect.TypeOf(s).Elem().Field(i).Name] = fieldVal
- }
- case reflect.String:
- fieldVal := fld.String()
- if fieldVal != "" {
- fields[reflect.TypeOf(s).Elem().Field(i).Name] = fieldVal
- }
- }
- }
- return fields
-}
-
-// MissingMapFields detects missing field values based on mandatory field names from a map[string]any
-func MissingMapFields(s map[string]any, mandatories []string) []string {
- missing := []string{}
- for _, fieldName := range mandatories {
- if fldval, has := s[fieldName]; !has {
- missing = append(missing, fieldName)
- } else {
- fld := reflect.ValueOf(fldval)
- // sanitize the string fields before checking
- if fld.Kind() == reflect.String && fld.CanSet() {
- fld.SetString(strings.TrimSpace(fld.String()))
- }
- if (fld.Kind() == reflect.String && fld.String() == "") ||
- ((fld.Kind() == reflect.Slice || fld.Kind() == reflect.Map) && fld.Len() == 0) ||
- (fld.Kind() == reflect.Int && fld.Int() == 0) {
- missing = append(missing, fieldName)
- }
- }
- }
- return missing
-}
-
-// Converts a struct to map
-/*func StrucToMap(s any) map[string]any {
- mp := make(map[string]any)
- for i := 0; i < reflect.ValueOf(s).Elem().NumField(); i++ {
- fld := reflect.ValueOf(s).Elem().Field(i)
- switch fld.Kind() {
- case reflect.Bool:
- mp[reflect.TypeOf(s).Elem().Field(i).Name] = fld.Bool()
- case reflect.Int:
- mp[reflect.TypeOf(s).Elem().Field(i).Name] = fld.Int()
- case reflect.String:
- mp[reflect.TypeOf(s).Elem().Field(i).Name] = fld.String()
- }
- }
- return mp
-}*/
-
-// Converts a struct to map[string]any
-func ToMapMapStringInterface(in any) map[string]any { // Got error and it is not used anywhere
- out := make(map[string]any)
-
- v := reflect.ValueOf(in)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- typ := reflect.TypeOf(in)
- for i := 0; i < v.NumField(); i++ {
- out[typ.Field(i).Name] = v.Field(i).Interface()
- }
- return out
-}
-
-// Converts a struct to map[string]string
-func ToMapStringString(in any) map[string]string {
- out := make(map[string]string)
-
- v := reflect.ValueOf(in)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- in = v.Interface()
- }
- typ := reflect.TypeOf(in)
- for i := 0; i < v.NumField(); i++ {
- // gets us a StructField
- typField := typ.Field(i)
- field := v.Field(i)
- if field.Kind() == reflect.String {
- out[typField.Name] = field.String()
- }
- }
- return out
-}
-
-func GetMapExtraFields(in any, extraFields string) map[string]string {
- out := make(map[string]string)
- v := reflect.ValueOf(in)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- field := v.FieldByName(extraFields)
- if field.Kind() == reflect.Map {
- keys := field.MapKeys()
- for _, key := range keys {
- out[key.String()] = field.MapIndex(key).String()
- }
- }
- return out
-}
-
-func SetMapExtraFields(in any, values map[string]string, extraFields string) {
- v := reflect.ValueOf(in)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- efField := v.FieldByName(extraFields)
- if efField.IsValid() && efField.Kind() == reflect.Map {
- keys := efField.MapKeys()
- for _, key := range keys {
- if efField.MapIndex(key).String() != "" {
- if val, found := values[key.String()]; found {
- efField.SetMapIndex(key, reflect.ValueOf(val))
- }
- }
- }
- }
-}
-
-func FromMapStringString(m map[string]string, in any) {
- v := reflect.ValueOf(in)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- for fieldName, fieldValue := range m {
- field := v.FieldByName(fieldName)
- if field.IsValid() {
- if field.Kind() == reflect.String {
- if field.String() != "" && field.CanSet() {
- field.SetString(fieldValue)
- }
- }
- }
- }
-}
-
-func FromMapStringInterface(m map[string]any, in any) error {
- v := reflect.ValueOf(in)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- for fieldName, fieldValue := range m {
- field := v.FieldByName(fieldName)
- if field.IsValid() {
- if !field.IsValid() || !field.CanSet() {
- continue
- }
- structFieldType := field.Type()
- val := reflect.ValueOf(fieldValue)
- if structFieldType != val.Type() {
- return errors.New("Provided value type didn't match obj field type")
- }
- field.Set(val)
- }
- }
- return nil
-}
-
-// initial intent was to use it with *cgr_rpc but does not handle slice and structure fields
-func FromMapStringInterfaceValue(m map[string]any, v reflect.Value) (any, error) {
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- for fieldName, fieldValue := range m {
- field := v.FieldByName(fieldName)
- if field.IsValid() {
- if !field.IsValid() || !field.CanSet() {
- continue
- }
- val := reflect.ValueOf(fieldValue)
- structFieldType := field.Type()
- if structFieldType.Kind() == reflect.Ptr {
- field.Set(reflect.New(field.Type().Elem()))
- field = field.Elem()
- }
- structFieldType = field.Type()
- if structFieldType != val.Type() {
- return nil, fmt.Errorf("provided value type didn't match obj field type: %v vs %v (%v vs %v)", structFieldType, val.Type(), structFieldType.Kind(), val.Type().Kind())
- }
- field.Set(val)
- }
- }
- return v.Interface(), nil
-}
-
-// Update struct with map fields, returns not matching map keys, s is a struct to be updated
-func UpdateStructWithStrMap(s any, m map[string]string) []string { // Not tested and declared and used only here
- notMatched := []string{}
- for key, val := range m {
- fld := reflect.ValueOf(s).Elem().FieldByName(key)
- if fld.IsValid() {
- switch fld.Kind() {
- case reflect.Bool:
- if valBool, err := strconv.ParseBool(val); err != nil {
- notMatched = append(notMatched, key)
- } else {
- fld.SetBool(valBool)
- }
- case reflect.Int:
- if valInt, err := strconv.ParseInt(val, 10, 64); err != nil {
- notMatched = append(notMatched, key)
- } else {
- fld.SetInt(valInt)
- }
- case reflect.String:
- fld.SetString(val)
- }
- } else {
- notMatched = append(notMatched, key)
- }
- }
- return notMatched
-}
-
-// UpdateStructWithIfaceMap will update struct fields with values coming from map
-// if map values are not matching the ones in struct convertion is being attempted
-// ToDo: add here more fields
-func UpdateStructWithIfaceMap(s any, mp map[string]any) (err error) {
- for key, val := range mp {
- fld := reflect.ValueOf(s).Elem().FieldByName(key)
- if fld.IsValid() {
- switch fld.Kind() {
- case reflect.Bool:
- if val == "" { // auto-populate defaults so we can parse empty strings
- val = false
- }
- if valBool, err := IfaceAsBool(val); err != nil {
- return err
- } else {
- fld.SetBool(valBool)
- }
- case reflect.Int, reflect.Int64:
- if val == "" {
- val = 0
- }
- if valInt, err := IfaceAsInt64(val); err != nil {
- return err
- } else {
- fld.SetInt(valInt)
- }
- case reflect.Float64:
- if val == "" {
- val = 0.0
- }
- if valFlt, err := IfaceAsFloat64(val); err != nil {
- return err
- } else {
- fld.SetFloat(valFlt)
- }
- case reflect.String:
- fld.SetString(IfaceAsString(val))
- default: // improper use of function
- return fmt.Errorf("cannot update unsupported struct field: %+v", fld)
- }
- }
- }
- return
-}
-
-
-
/*
-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 utils
-
-import (
- "encoding/json"
- "errors"
- "log"
- "strconv"
- "time"
-)
-
-// for computing a dynamic value for Value field
-type ValueFormula struct {
- Method string
- Params map[string]any
- Static float64
-}
-
-func ParseBalanceFilterValue(tor string, val string) (*ValueFormula, error) {
- if tor == VOICE { // VOICE balance is parsed as nanoseconds with support for time duration strings
- if d, err := ParseDurationWithNanosecs(val); err == nil {
- return &ValueFormula{Static: float64(d.Nanoseconds())}, err
- }
- } else if u, err := strconv.ParseFloat(val, 64); err == nil {
- return &ValueFormula{Static: u}, err
- }
- var vf ValueFormula
- if err := json.Unmarshal([]byte(val), &vf); err == nil {
- return &vf, err
- }
- return nil, errors.New("Invalid value: " + val)
-}
-
-type valueFormula func(map[string]any) float64
-
-const (
- INCREMENTAL = "*incremental"
-)
-
-var ValueFormulas = map[string]valueFormula{
- INCREMENTAL: incrementalFormula,
-}
-
-func (vf *ValueFormula) String() string {
- return ToJSON(vf)
-}
-
-func incrementalFormula(params map[string]any) float64 {
- // check parameters
- unitsInterface, unitsFound := params["Units"]
- intervalInterface, intervalFound := params["Interval"]
- incrementInterface, incrementFound := params["Increment"]
-
- if !unitsFound || !intervalFound || !incrementFound {
- return 0.0
- }
- units, ok := unitsInterface.(float64)
- if !ok {
- log.Print("units")
- return 0.0
- }
- var interval string
- switch intr := intervalInterface.(type) {
- case string:
- interval = intr
- case []byte:
- interval = string(intr)
- default:
- return 0.0
- }
- var increment string
- switch incr := incrementInterface.(type) {
- case string:
- increment = incr
- case []byte:
- increment = string(incr)
- default:
- return 0.0
- }
- now := time.Now()
- if increment == "day" {
- if interval == "week" {
- return units / 7
- }
- if interval == "month" {
- return units / DaysInMonth(now.Year(), now.Month())
- }
- if interval == "year" {
- return units / DaysInYear(now.Year())
- }
- }
- if increment == "hour" {
- if interval == "day" {
- return units / 24
- }
- if interval == "month" {
- return units / (DaysInMonth(now.Year(), now.Month()) * 24)
- }
- if interval == "year" {
- return units / (DaysInYear(now.Year()) * 24)
- }
- }
- if increment == "minute" {
- if interval == "hour" {
- return units / 60
- }
- }
- return 0.0
-}
-
-
-
-
-
-
diff --git a/utils/slice_test.go b/utils/slice_test.go
index cf46c8800..d28525646 100644
--- a/utils/slice_test.go
+++ b/utils/slice_test.go
@@ -91,6 +91,57 @@ func TestAvg(t *testing.T) {
}
}
+func TestAvgNegative(t *testing.T) {
+ tests := []struct {
+ name string
+ args []float64
+ want float64
+ }{
+ {
+ name: "no data",
+ args: []float64{},
+ want: -1,
+ },
+ {
+ name: "testing AvgNegative",
+ args: []float64{-1,0,4},
+ want: 1,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := AvgNegative(tt.args); got != tt.want {
+ t.Errorf("AvgNegative() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestPrefixSliceItems(t *testing.T) {
+ type args struct {
+ slc []string
+ prfx string
+ }
+ tests := []struct {
+ name string
+ args args
+ wantOut []string
+ }{
+ {
+ name: "testing PrefixSliceItems",
+ args: args{[]string{"test1", "test2"}, "!"},
+ wantOut: []string{"!test1", "!test2"},
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if gotOut := PrefixSliceItems(tt.args.slc, tt.args.prfx); !reflect.DeepEqual(gotOut, tt.wantOut) {
+ t.Errorf("PrefixSliceItems() = %v, want %v", gotOut, tt.wantOut)
+ }
+ })
+ }
+}
+
func TestAvgEmpty(t *testing.T) {
values := []float64{}
result := Avg(values)