diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 1c1da74d7..7563fa0c9 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -668,6 +668,8 @@ func main() { } engine.SetRoundingDecimals(cfg.RoundingDecimals) + engine.SetRpSubjectPrefixMatching(cfg.RpSubjectPrefixMatching) + engine.SetLcrSubjectPrefixMatching(cfg.LcrSubjectPrefixMatching) stopHandled := false // Rpc/http server diff --git a/config/config.go b/config/config.go index 72a1bf98c..d2dbd6486 100644 --- a/config/config.go +++ b/config/config.go @@ -167,89 +167,90 @@ func NewCGRConfigFromFolder(cfgDir string) (*CGRConfig, error) { // Holds system configuration, defaults are overwritten with values from config file if found type CGRConfig struct { - TpDbType string - TpDbHost string // The host to connect to. Values that start with / are for UNIX domain sockets. - TpDbPort string // The port to bind to. - TpDbName string // The name of the database to connect to. - TpDbUser string // The user to sign in as. - TpDbPass string // The user's password. - DataDbType string - DataDbHost string // The host to connect to. Values that start with / are for UNIX domain sockets. - DataDbPort string // The port to bind to. - DataDbName string // The name of the database to connect to. - DataDbUser string // The user to sign in as. - DataDbPass string // The user's password. - LoadHistorySize int // Maximum number of records to archive in load history - StorDBType string // Should reflect the database type used to store logs - StorDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets. - StorDBPort string // Th e port to bind to. - StorDBName string // The name of the database to connect to. - StorDBUser string // The user to sign in as. - StorDBPass string // The user's password. - StorDBMaxOpenConns int // Maximum database connections opened - StorDBMaxIdleConns int // Maximum idle connections to keep opened - StorDBCDRSIndexes []string - DBDataEncoding string // The encoding used to store object data in strings: - RPCJSONListen string // RPC JSON listening address - RPCGOBListen string // RPC GOB listening address - HTTPListen string // HTTP listening address - DefaultReqType string // Use this request type if not defined on top - DefaultCategory string // set default type of record - DefaultTenant string // set default tenant - DefaultSubject string // set default rating subject, useful in case of fallback - DefaultTimezone string // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB> - Reconnects int // number of recconect attempts in case of connection lost <-1 for infinite | nb> - ConnectAttempts int // number of initial connection attempts before giving up - ResponseCacheTTL time.Duration // the life span of a cached response - InternalTtl time.Duration // maximum duration to wait for internal connections before giving up - RoundingDecimals int // Number of decimals to round end prices at - HttpSkipTlsVerify bool // If enabled Http Client will accept any TLS certificate - TpExportPath string // Path towards export folder for offline Tariff Plans - HttpFailedDir string // Directory path where we store failed http requests - MaxCallDuration time.Duration // The maximum call duration (used by responder when querying DerivedCharging) // ToDo: export it in configuration file - RaterEnabled bool // start standalone server (no balancer) - RaterBalancer string // balancer address host:port - RaterCdrStats string // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> - RaterHistoryServer string - RaterPubSubServer string - RaterUserServer string - RaterAliasesServer string - RpSubjectPrefixMatching bool // enables prefix matching for the rating profile subject - BalancerEnabled bool - SchedulerEnabled bool - CDRSEnabled bool // Enable CDR Server service - CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs - CDRSStoreCdrs bool // store cdrs in storDb - CDRSRater string // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234> - CDRSPubSub string // address where to reach the pubsub service: <""|internal|x.y.z.y:1234> - CDRSUsers string // address where to reach the users service: <""|internal|x.y.z.y:1234> - CDRSAliases string // address where to reach the aliases service: <""|internal|x.y.z.y:1234> - CDRSStats string // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> - CDRSCdrReplication []*CdrReplicationCfg // Replicate raw CDRs to a number of servers - CDRStatsEnabled bool // Enable CDR Stats service - CDRStatsSaveInterval time.Duration // Save interval duration - CdreProfiles map[string]*CdreConfig - CdrcProfiles map[string]map[string]*CdrcConfig // Number of CDRC instances running imports, format map[dirPath]map[instanceName]{Configs} - SmGenericConfig *SmGenericConfig - SmFsConfig *SmFsConfig // SM-FreeSWITCH configuration - SmKamConfig *SmKamConfig // SM-Kamailio Configuration - SmOsipsConfig *SmOsipsConfig // SM-OpenSIPS Configuration - diameterAgentCfg *DiameterAgentCfg // DiameterAgent configuration - HistoryServer string // Address where to reach the master history server: - HistoryServerEnabled bool // Starts History as server: . - HistoryDir string // Location on disk where to store history files. - HistorySaveInterval time.Duration // The timout duration between pubsub writes - PubSubServerEnabled bool // Starts PubSub as server: . - AliasesServerEnabled bool // Starts PubSub as server: . - UserServerEnabled bool // Starts User as server: - UserServerIndexes []string // List of user profile field indexes - MailerServer string // The server to use when sending emails out - MailerAuthUser string // Authenticate to email server using this user - MailerAuthPass string // Authenticate to email server with this password - MailerFromAddr string // From address used when sending emails out - DataFolderPath string // Path towards data folder, for tests internal usage, not loading out of .json options - sureTaxCfg *SureTaxCfg // Load here SureTax configuration, as pointer so we can have runtime reloads in the future - ConfigReloads map[string]chan struct{} // Signals to specific entities that a config reload should occur + TpDbType string + TpDbHost string // The host to connect to. Values that start with / are for UNIX domain sockets. + TpDbPort string // The port to bind to. + TpDbName string // The name of the database to connect to. + TpDbUser string // The user to sign in as. + TpDbPass string // The user's password. + DataDbType string + DataDbHost string // The host to connect to. Values that start with / are for UNIX domain sockets. + DataDbPort string // The port to bind to. + DataDbName string // The name of the database to connect to. + DataDbUser string // The user to sign in as. + DataDbPass string // The user's password. + LoadHistorySize int // Maximum number of records to archive in load history + StorDBType string // Should reflect the database type used to store logs + StorDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets. + StorDBPort string // Th e port to bind to. + StorDBName string // The name of the database to connect to. + StorDBUser string // The user to sign in as. + StorDBPass string // The user's password. + StorDBMaxOpenConns int // Maximum database connections opened + StorDBMaxIdleConns int // Maximum idle connections to keep opened + StorDBCDRSIndexes []string + DBDataEncoding string // The encoding used to store object data in strings: + RPCJSONListen string // RPC JSON listening address + RPCGOBListen string // RPC GOB listening address + HTTPListen string // HTTP listening address + DefaultReqType string // Use this request type if not defined on top + DefaultCategory string // set default type of record + DefaultTenant string // set default tenant + DefaultSubject string // set default rating subject, useful in case of fallback + DefaultTimezone string // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB> + Reconnects int // number of recconect attempts in case of connection lost <-1 for infinite | nb> + ConnectAttempts int // number of initial connection attempts before giving up + ResponseCacheTTL time.Duration // the life span of a cached response + InternalTtl time.Duration // maximum duration to wait for internal connections before giving up + RoundingDecimals int // Number of decimals to round end prices at + HttpSkipTlsVerify bool // If enabled Http Client will accept any TLS certificate + TpExportPath string // Path towards export folder for offline Tariff Plans + HttpFailedDir string // Directory path where we store failed http requests + MaxCallDuration time.Duration // The maximum call duration (used by responder when querying DerivedCharging) // ToDo: export it in configuration file + RaterEnabled bool // start standalone server (no balancer) + RaterBalancer string // balancer address host:port + RaterCdrStats string // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> + RaterHistoryServer string + RaterPubSubServer string + RaterUserServer string + RaterAliasesServer string + RpSubjectPrefixMatching bool // enables prefix matching for the rating profile subject + LcrSubjectPrefixMatching bool // enables prefix matching for the lcr subject + BalancerEnabled bool + SchedulerEnabled bool + CDRSEnabled bool // Enable CDR Server service + CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs + CDRSStoreCdrs bool // store cdrs in storDb + CDRSRater string // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234> + CDRSPubSub string // address where to reach the pubsub service: <""|internal|x.y.z.y:1234> + CDRSUsers string // address where to reach the users service: <""|internal|x.y.z.y:1234> + CDRSAliases string // address where to reach the aliases service: <""|internal|x.y.z.y:1234> + CDRSStats string // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> + CDRSCdrReplication []*CdrReplicationCfg // Replicate raw CDRs to a number of servers + CDRStatsEnabled bool // Enable CDR Stats service + CDRStatsSaveInterval time.Duration // Save interval duration + CdreProfiles map[string]*CdreConfig + CdrcProfiles map[string]map[string]*CdrcConfig // Number of CDRC instances running imports, format map[dirPath]map[instanceName]{Configs} + SmGenericConfig *SmGenericConfig + SmFsConfig *SmFsConfig // SM-FreeSWITCH configuration + SmKamConfig *SmKamConfig // SM-Kamailio Configuration + SmOsipsConfig *SmOsipsConfig // SM-OpenSIPS Configuration + diameterAgentCfg *DiameterAgentCfg // DiameterAgent configuration + HistoryServer string // Address where to reach the master history server: + HistoryServerEnabled bool // Starts History as server: . + HistoryDir string // Location on disk where to store history files. + HistorySaveInterval time.Duration // The timout duration between pubsub writes + PubSubServerEnabled bool // Starts PubSub as server: . + AliasesServerEnabled bool // Starts PubSub as server: . + UserServerEnabled bool // Starts User as server: + UserServerIndexes []string // List of user profile field indexes + MailerServer string // The server to use when sending emails out + MailerAuthUser string // Authenticate to email server using this user + MailerAuthPass string // Authenticate to email server with this password + MailerFromAddr string // From address used when sending emails out + DataFolderPath string // Path towards data folder, for tests internal usage, not loading out of .json options + sureTaxCfg *SureTaxCfg // Load here SureTax configuration, as pointer so we can have runtime reloads in the future + ConfigReloads map[string]chan struct{} // Signals to specific entities that a config reload should occur // Cache defaults loaded from json and needing clones dfltCdreProfile *CdreConfig // Default cdreConfig profile dfltCdrcProfile *CdrcConfig // Default cdrcConfig profile @@ -670,6 +671,9 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error { if jsnRaterCfg.Rp_subject_prefix_matching != nil { self.RpSubjectPrefixMatching = *jsnRaterCfg.Rp_subject_prefix_matching } + if jsnRaterCfg.Lcr_subject_prefix_matching != nil { + self.LcrSubjectPrefixMatching = *jsnRaterCfg.Lcr_subject_prefix_matching + } } if jsnBalancerCfg != nil && jsnBalancerCfg.Enabled != nil { diff --git a/config/config_defaults.go b/config/config_defaults.go index f79ef663b..a0caa38b5 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -99,7 +99,8 @@ const CGRATES_CFG_JSON = ` "pubsubs": "", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234> "users": "", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234> "aliases": "", // address where to reach the aliases service, empty to disable aliases functionality: <""|internal|x.y.z.y:1234> - "rp_subject_prefix_matching": false // enables prefix matching for the rating profile subject + "rp_subject_prefix_matching": false, // enables prefix matching for the rating profile subject + "lcr_subject_prefix_matching": false // enables prefix matching for the lcr subject }, diff --git a/config/config_json_test.go b/config/config_json_test.go index 9238aae39..e80cb6aaa 100644 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -129,7 +129,7 @@ func TestDfBalancerJsonCfg(t *testing.T) { func TestDfRaterJsonCfg(t *testing.T) { eCfg := &RaterJsonCfg{Enabled: utils.BoolPointer(false), Balancer: utils.StringPointer(""), Cdrstats: utils.StringPointer(""), - Historys: utils.StringPointer(""), Pubsubs: utils.StringPointer(""), Users: utils.StringPointer(""), Aliases: utils.StringPointer(""), Rp_subject_prefix_matching: utils.BoolPointer(false)} + Historys: utils.StringPointer(""), Pubsubs: utils.StringPointer(""), Users: utils.StringPointer(""), Aliases: utils.StringPointer(""), Rp_subject_prefix_matching: utils.BoolPointer(false), Lcr_subject_prefix_matching: utils.BoolPointer(false)} if cfg, err := dfCgrJsonCfg.RaterJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfg, cfg) { diff --git a/config/libconfig_json.go b/config/libconfig_json.go index bc94bca2d..e40dedcdd 100644 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -64,14 +64,15 @@ type BalancerJsonCfg struct { // Rater config section type RaterJsonCfg struct { - Enabled *bool - Balancer *string - Cdrstats *string - Historys *string - Pubsubs *string - Aliases *string - Users *string - Rp_subject_prefix_matching *bool + Enabled *bool + Balancer *string + Cdrstats *string + Historys *string + Pubsubs *string + Aliases *string + Users *string + Rp_subject_prefix_matching *bool + Lcr_subject_prefix_matching *bool } // Scheduler config section diff --git a/data/conf/cgrates/cgrates.json b/data/conf/cgrates/cgrates.json index bc740467c..4e7790c06 100644 --- a/data/conf/cgrates/cgrates.json +++ b/data/conf/cgrates/cgrates.json @@ -77,7 +77,8 @@ // "pubsubs": "", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234> // "users": "", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234> // "aliases": "", // address where to reach the aliases service, empty to disable aliases functionality: <""|internal|x.y.z.y:1234> -// "rp_subject_prefix_matching": false, // enables prefix matching for the rating profile subject +// "rp_subject_prefix_matching": false, // enables prefix matching for the rating profile subject, +// "lcr_subject_prefix_matching": false, // enables prefix matching for the lcr subject //}, diff --git a/engine/calldesc.go b/engine/calldesc.go index 9ab8a9373..fca3a671d 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -70,17 +70,18 @@ func init() { } var ( - ratingStorage RatingStorage - accountingStorage AccountingStorage - storageLogger LogStorage - cdrStorage CdrStorage - debitPeriod = 10 * time.Second - globalRoundingDecimals = 6 - historyScribe history.Scribe - pubSubServer rpcclient.RpcClientConnection - userService UserService - aliasService AliasService - rpSubjectPrefixMatching bool + ratingStorage RatingStorage + accountingStorage AccountingStorage + storageLogger LogStorage + cdrStorage CdrStorage + debitPeriod = 10 * time.Second + globalRoundingDecimals = 6 + historyScribe history.Scribe + pubSubServer rpcclient.RpcClientConnection + userService UserService + aliasService AliasService + rpSubjectPrefixMatching bool + lcrSubjectPrefixMatching bool ) // Exported method to set the storage getter. @@ -101,6 +102,10 @@ func SetRpSubjectPrefixMatching(flag bool) { rpSubjectPrefixMatching = flag } +func SetLcrSubjectPrefixMatching(flag bool) { + lcrSubjectPrefixMatching = flag +} + /* Sets the database for logging (can be de same as storage getter or different db) */ @@ -924,6 +929,15 @@ func (cd *CallDescriptor) GetLCRFromStorage() (*LCR, error) { utils.LCRKey(cd.Direction, utils.ANY, utils.ANY, utils.ANY, utils.ANY), utils.LCRKey(utils.ANY, utils.ANY, utils.ANY, utils.ANY, utils.ANY), } + if lcrSubjectPrefixMatching { + var partialSubjects []string + lenSubject := len(cd.Subject) + for i := 1; i < lenSubject; i++ { + partialSubjects = append(partialSubjects, utils.LCRKey(cd.Direction, cd.Tenant, cd.Category, cd.Account, cd.Subject[:lenSubject-i])) + } + // insert partialsubjects into keyVariants + keyVariants = append(keyVariants[:1], append(partialSubjects, keyVariants[1:]...)...) + } for _, key := range keyVariants { if lcr, err := ratingStorage.GetLCR(key, false); err != nil && err != utils.ErrNotFound { return nil, err diff --git a/engine/lcr_test.go b/engine/lcr_test.go index ddf112efb..49f201cff 100644 --- a/engine/lcr_test.go +++ b/engine/lcr_test.go @@ -210,6 +210,24 @@ func TestLcrGet(t *testing.T) { } } +func TestLcrGetPrefix(t *testing.T) { + lcrSubjectPrefixMatching = true + cd := &CallDescriptor{ + TimeStart: time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC), + TimeEnd: time.Date(2015, 04, 06, 17, 41, 0, 0, time.UTC), + Tenant: "cgrates.org", + Direction: "*in", + Category: "call", + Destination: "0723098765", + Account: "rif", + Subject: "rifus", + } + lcr, err := cd.GetLCR(nil, nil) + if err != nil || lcr == nil { + t.Errorf("Bad lcr: %+v, %v", lcr, err) + } +} + func TestLcrRequestAsCallDescriptor(t *testing.T) { sTime := time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC) callDur := time.Duration(1) * time.Minute diff --git a/engine/ratingprofile.go b/engine/ratingprofile.go index f0ebf0ac3..2560e96c0 100644 --- a/engine/ratingprofile.go +++ b/engine/ratingprofile.go @@ -256,8 +256,9 @@ func RatingProfileSubjectPrefixMatching(key string) (rp *RatingProfile, err erro lastIndex := strings.LastIndex(key, utils.CONCATENATED_KEY_SEP) baseKey := key[:lastIndex] subject := key[lastIndex:] - for i := 1; i < len(subject)-1; i++ { - if rp, err = ratingStorage.GetRatingProfile(baseKey+subject[:len(subject)-i], false); err == nil { + lenSubject := len(subject) + for i := 1; i < lenSubject-1; i++ { + if rp, err = ratingStorage.GetRatingProfile(baseKey+subject[:lenSubject-i], false); err == nil { return rp, err } }