LCR subject prefix matching

fixes #388, fixes #394
This commit is contained in:
Radu Ioan Fericean
2016-04-01 13:25:54 +03:00
parent eff6f193b5
commit f49c1f694c
9 changed files with 149 additions and 107 deletions

View File

@@ -668,6 +668,8 @@ func main() {
}
engine.SetRoundingDecimals(cfg.RoundingDecimals)
engine.SetRpSubjectPrefixMatching(cfg.RpSubjectPrefixMatching)
engine.SetLcrSubjectPrefixMatching(cfg.LcrSubjectPrefixMatching)
stopHandled := false
// Rpc/http server

View File

@@ -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: <msgpack|json>
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: <internal|x.y.z.y:1234>
HistoryServerEnabled bool // Starts History as server: <true|false>.
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: <true|false>.
AliasesServerEnabled bool // Starts PubSub as server: <true|false>.
UserServerEnabled bool // Starts User as server: <true|false>
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: <msgpack|json>
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: <internal|x.y.z.y:1234>
HistoryServerEnabled bool // Starts History as server: <true|false>.
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: <true|false>.
AliasesServerEnabled bool // Starts PubSub as server: <true|false>.
UserServerEnabled bool // Starts User as server: <true|false>
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 {

View File

@@ -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
},

View File

@@ -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) {

View File

@@ -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

View File

@@ -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
//},

View File

@@ -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

View File

@@ -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

View File

@@ -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
}
}