mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Refactoring the code around derived charging to support integration with responder for internal requests, some of the copyright headers updated with new slogan
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
## Rating system for Telecom & ISP environments ##
|
||||
## Real-time Charging System for Telecom & ISP environments ##
|
||||
|
||||
[](https://drone.io/github.com/cgrates/cgrates/latest) [](http://travis-ci.org/cgrates/cgrates)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
@@ -119,37 +119,38 @@ type CGRConfig struct {
|
||||
CdrcExtraFields []string // Extra fields to extract, special format in case of .csv "field1:index1,field2:index2"
|
||||
SMEnabled bool
|
||||
SMSwitchType string
|
||||
SMRater string // address where to access rater. Can be internal, direct rater address or the address of a balancer
|
||||
SMRaterReconnects int // Number of reconnect attempts to rater
|
||||
SMDebitInterval int // the period to be debited in advanced during a call (in seconds)
|
||||
SMMaxCallDuration time.Duration // The maximum duration of a call
|
||||
MediatorEnabled bool // Starts Mediator service: <true|false>.
|
||||
MediatorRater string // Address where to reach the Rater: <internal|x.y.z.y:1234>
|
||||
MediatorRaterReconnects int // Number of reconnects to rater before giving up.
|
||||
MediatorRunIds []string // Identifiers for each mediation run on CDRs
|
||||
MediatorReqTypeFields []string // Name of request type fields to be used during mediation. Use index number in case of .csv cdrs.
|
||||
MediatorDirectionFields []string // Name of direction fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorTenantFields []string // Name of tenant fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorTORFields []string // Name of tor fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorAccountFields []string // Name of account fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorSubjectFields []string // Name of subject fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorDestFields []string // Name of destination fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorSetupTimeFields []string // Name of setup_time fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorAnswerTimeFields []string // Name of answer_time fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorDurationFields []string // Name of duration fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
DerivedChargers DerivedChargers // System wide derived chargers, added to the account level ones
|
||||
FreeswitchServer string // freeswitch address host:port
|
||||
FreeswitchPass string // FS socket password
|
||||
FreeswitchReconnects int // number of times to attempt reconnect after connect fails
|
||||
HistoryAgentEnabled bool // Starts History as an agent: <true|false>.
|
||||
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 history writes
|
||||
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
|
||||
SMRater string // address where to access rater. Can be internal, direct rater address or the address of a balancer
|
||||
SMRaterReconnects int // Number of reconnect attempts to rater
|
||||
SMDebitInterval int // the period to be debited in advanced during a call (in seconds)
|
||||
SMMaxCallDuration time.Duration // The maximum duration of a call
|
||||
MediatorEnabled bool // Starts Mediator service: <true|false>.
|
||||
MediatorRater string // Address where to reach the Rater: <internal|x.y.z.y:1234>
|
||||
MediatorRaterReconnects int // Number of reconnects to rater before giving up.
|
||||
MediatorRunIds []string // Identifiers for each mediation run on CDRs
|
||||
MediatorReqTypeFields []string // Name of request type fields to be used during mediation. Use index number in case of .csv cdrs.
|
||||
MediatorDirectionFields []string // Name of direction fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorTenantFields []string // Name of tenant fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorTORFields []string // Name of tor fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorAccountFields []string // Name of account fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorSubjectFields []string // Name of subject fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorDestFields []string // Name of destination fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorSetupTimeFields []string // Name of setup_time fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorAnswerTimeFields []string // Name of answer_time fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
MediatorDurationFields []string // Name of duration fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
DerivedChargers utils.DerivedChargers // System wide derived chargers, added to the account level ones
|
||||
CombinedDerivedChargers bool // Combine accounts specific derived_chargers with server configured
|
||||
FreeswitchServer string // freeswitch address host:port
|
||||
FreeswitchPass string // FS socket password
|
||||
FreeswitchReconnects int // number of times to attempt reconnect after connect fails
|
||||
HistoryAgentEnabled bool // Starts History as an agent: <true|false>.
|
||||
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 history writes
|
||||
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
|
||||
}
|
||||
|
||||
func (self *CGRConfig) setDefaults() error {
|
||||
@@ -217,7 +218,8 @@ func (self *CGRConfig) setDefaults() error {
|
||||
self.MediatorEnabled = false
|
||||
self.MediatorRater = "internal"
|
||||
self.MediatorRaterReconnects = 3
|
||||
self.DerivedChargers = make(DerivedChargers, 0)
|
||||
self.DerivedChargers = make(utils.DerivedChargers, 0)
|
||||
self.CombinedDerivedChargers = true
|
||||
self.SMEnabled = false
|
||||
self.SMSwitchType = FS
|
||||
self.SMRater = "internal"
|
||||
@@ -573,6 +575,9 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
if cfg.DerivedChargers, err = ParseCfgDerivedCharging(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hasOpt = c.HasOption("derived_charging", "combined_chargers"); hasOpt {
|
||||
cfg.CombinedDerivedChargers, _ = c.GetBool("derived_charging", "combined_chargers")
|
||||
}
|
||||
if hasOpt = c.HasOption("history_agent", "enabled"); hasOpt {
|
||||
cfg.HistoryAgentEnabled, _ = c.GetBool("history_agent", "enabled")
|
||||
}
|
||||
|
||||
@@ -119,7 +119,8 @@ func TestDefaults(t *testing.T) {
|
||||
eCfg.FreeswitchServer = "127.0.0.1:8021"
|
||||
eCfg.FreeswitchPass = "ClueCon"
|
||||
eCfg.FreeswitchReconnects = 5
|
||||
eCfg.DerivedChargers = make(DerivedChargers, 0)
|
||||
eCfg.DerivedChargers = make(utils.DerivedChargers, 0)
|
||||
eCfg.CombinedDerivedChargers = true
|
||||
eCfg.HistoryAgentEnabled = false
|
||||
eCfg.HistoryServer = "internal"
|
||||
eCfg.HistoryServerEnabled = false
|
||||
@@ -252,8 +253,9 @@ func TestConfigFromFile(t *testing.T) {
|
||||
eCfg.FreeswitchServer = "test"
|
||||
eCfg.FreeswitchPass = "test"
|
||||
eCfg.FreeswitchReconnects = 99
|
||||
eCfg.DerivedChargers = DerivedChargers{&DerivedCharger{RunId: "test", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
|
||||
eCfg.DerivedChargers = utils.DerivedChargers{&utils.DerivedCharger{RunId: "test", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
|
||||
TorField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", DurationField: "test"}}
|
||||
eCfg.CombinedDerivedChargers = true
|
||||
eCfg.HistoryAgentEnabled = true
|
||||
eCfg.HistoryServer = "test"
|
||||
eCfg.HistoryServerEnabled = true
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2012-2014 ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can Storagetribute 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 WITH*out 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 config
|
||||
|
||||
import (
|
||||
"code.google.com/p/goconf/conf"
|
||||
"errors"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Wraps regexp compiling in case of rsr fields
|
||||
func NewDerivedCharger(runId, reqTypeFld, dirFld, tenantFld, totFld, acntFld, subjFld, dstFld, sTimeFld, aTimeFld, durFld string) (dc *DerivedCharger, err error) {
|
||||
if len(runId) == 0 {
|
||||
return nil, errors.New("Empty run id field")
|
||||
}
|
||||
dc = &DerivedCharger{RunId: runId}
|
||||
dc.ReqTypeField = reqTypeFld
|
||||
if strings.HasPrefix(dc.ReqTypeField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrReqTypeField, err = utils.NewRSRField(dc.ReqTypeField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.DirectionField = dirFld
|
||||
if strings.HasPrefix(dc.DirectionField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrDirectionField, err = utils.NewRSRField(dc.DirectionField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.TenantField = tenantFld
|
||||
if strings.HasPrefix(dc.TenantField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrTenantField, err = utils.NewRSRField(dc.TenantField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.TorField = totFld
|
||||
if strings.HasPrefix(dc.TorField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrTorField, err = utils.NewRSRField(dc.TorField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.AccountField = acntFld
|
||||
if strings.HasPrefix(dc.AccountField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrAccountField, err = utils.NewRSRField(dc.AccountField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.SubjectField = subjFld
|
||||
if strings.HasPrefix(dc.SubjectField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrSubjectField, err = utils.NewRSRField(dc.SubjectField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.DestinationField = dstFld
|
||||
if strings.HasPrefix(dc.DestinationField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrDestinationField, err = utils.NewRSRField(dc.DestinationField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.SetupTimeField = sTimeFld
|
||||
if strings.HasPrefix(dc.SetupTimeField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrSetupTimeField, err = utils.NewRSRField(dc.SetupTimeField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.AnswerTimeField = aTimeFld
|
||||
if strings.HasPrefix(dc.AnswerTimeField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrAnswerTimeField, err = utils.NewRSRField(dc.AnswerTimeField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.DurationField = durFld
|
||||
if strings.HasPrefix(dc.DurationField, utils.REGEXP_PREFIX) {
|
||||
if dc.rsrDurationField, err = utils.NewRSRField(dc.DurationField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return dc, nil
|
||||
}
|
||||
|
||||
type DerivedCharger struct {
|
||||
RunId string // Unique runId in the chain
|
||||
ReqTypeField string // Field containing request type info, number in case of csv source, '^' as prefix in case of static values
|
||||
DirectionField string // Field containing direction info
|
||||
TenantField string // Field containing tenant info
|
||||
TorField string // Field containing tor info
|
||||
AccountField string // Field containing account information
|
||||
SubjectField string // Field containing subject information
|
||||
DestinationField string // Field containing destination information
|
||||
SetupTimeField string // Field containing setup time information
|
||||
AnswerTimeField string // Field containing answer time information
|
||||
DurationField string // Field containing duration information
|
||||
rsrReqTypeField *utils.RSRField // Storage for compiled Regexp in case of RSRFields
|
||||
rsrDirectionField *utils.RSRField
|
||||
rsrTenantField *utils.RSRField
|
||||
rsrTorField *utils.RSRField
|
||||
rsrAccountField *utils.RSRField
|
||||
rsrSubjectField *utils.RSRField
|
||||
rsrDestinationField *utils.RSRField
|
||||
rsrSetupTimeField *utils.RSRField
|
||||
rsrAnswerTimeField *utils.RSRField
|
||||
rsrDurationField *utils.RSRField
|
||||
}
|
||||
|
||||
type DerivedChargers []*DerivedCharger
|
||||
|
||||
// Precheck that RunId is unique
|
||||
func (dcs DerivedChargers) Append(dc *DerivedCharger) (DerivedChargers, error) {
|
||||
if dc.RunId == utils.DEFAULT_RUNID {
|
||||
return nil, errors.New("Reserved RunId")
|
||||
}
|
||||
for _, dcLocal := range dcs {
|
||||
if dcLocal.RunId == dc.RunId {
|
||||
return nil, errors.New("Duplicated RunId")
|
||||
}
|
||||
}
|
||||
return append(dcs, dc), nil
|
||||
}
|
||||
|
||||
// Parse the configuration file and returns DerivedChargers instance if no errors
|
||||
func ParseCfgDerivedCharging(c *conf.ConfigFile) (dcs DerivedChargers, err error) {
|
||||
var runIds, reqTypeFlds, directionFlds, tenantFlds, torFlds, acntFlds, subjFlds, dstFlds, sTimeFlds, aTimeFlds, durFlds []string
|
||||
cfgVal, _ := c.GetString("derived_charging", "run_ids")
|
||||
if runIds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "reqtype_fields")
|
||||
if reqTypeFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "direction_fields")
|
||||
if directionFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "tenant_fields")
|
||||
if tenantFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "tor_fields")
|
||||
if torFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "account_fields")
|
||||
if acntFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "subject_fields")
|
||||
if subjFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "destination_fields")
|
||||
if dstFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "setup_time_fields")
|
||||
if sTimeFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "answer_time_fields")
|
||||
if aTimeFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "duration_fields")
|
||||
if durFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// We need all to be the same length
|
||||
if len(reqTypeFlds) != len(runIds) ||
|
||||
len(directionFlds) != len(runIds) ||
|
||||
len(tenantFlds) != len(runIds) ||
|
||||
len(torFlds) != len(runIds) ||
|
||||
len(acntFlds) != len(runIds) ||
|
||||
len(subjFlds) != len(runIds) ||
|
||||
len(dstFlds) != len(runIds) ||
|
||||
len(sTimeFlds) != len(runIds) ||
|
||||
len(aTimeFlds) != len(runIds) ||
|
||||
len(durFlds) != len(runIds) {
|
||||
return nil, errors.New("<ConfigSanity> Inconsistent fields length in derivated_charging section")
|
||||
}
|
||||
// Create the individual chargers and append them to the final instance
|
||||
dcs = make(DerivedChargers, 0)
|
||||
for runIdx, runId := range runIds {
|
||||
dc, err := NewDerivedCharger(runId, reqTypeFlds[runIdx], directionFlds[runIdx], tenantFlds[runIdx], torFlds[runIdx],
|
||||
acntFlds[runIdx], subjFlds[runIdx], dstFlds[runIdx], sTimeFlds[runIdx], aTimeFlds[runIdx], durFlds[runIdx])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dcs, err = dcs.Append(dc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return dcs, nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package config
|
||||
|
||||
import (
|
||||
"code.google.com/p/goconf/conf"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
@@ -60,3 +61,78 @@ func ParseRSRFields(configVal string) ([]*utils.RSRField, error) {
|
||||
}
|
||||
return rsrFields, nil
|
||||
}
|
||||
|
||||
// Parse the configuration file and returns utils.DerivedChargers instance if no errors
|
||||
func ParseCfgDerivedCharging(c *conf.ConfigFile) (dcs utils.DerivedChargers, err error) {
|
||||
var runIds, reqTypeFlds, directionFlds, tenantFlds, torFlds, acntFlds, subjFlds, dstFlds, sTimeFlds, aTimeFlds, durFlds []string
|
||||
cfgVal, _ := c.GetString("derived_charging", "run_ids")
|
||||
if runIds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "reqtype_fields")
|
||||
if reqTypeFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "direction_fields")
|
||||
if directionFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "tenant_fields")
|
||||
if tenantFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "tor_fields")
|
||||
if torFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "account_fields")
|
||||
if acntFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "subject_fields")
|
||||
if subjFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "destination_fields")
|
||||
if dstFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "setup_time_fields")
|
||||
if sTimeFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "answer_time_fields")
|
||||
if aTimeFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "duration_fields")
|
||||
if durFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// We need all to be the same length
|
||||
if len(reqTypeFlds) != len(runIds) ||
|
||||
len(directionFlds) != len(runIds) ||
|
||||
len(tenantFlds) != len(runIds) ||
|
||||
len(torFlds) != len(runIds) ||
|
||||
len(acntFlds) != len(runIds) ||
|
||||
len(subjFlds) != len(runIds) ||
|
||||
len(dstFlds) != len(runIds) ||
|
||||
len(sTimeFlds) != len(runIds) ||
|
||||
len(aTimeFlds) != len(runIds) ||
|
||||
len(durFlds) != len(runIds) {
|
||||
return nil, errors.New("<ConfigSanity> Inconsistent fields length in derivated_charging section")
|
||||
}
|
||||
// Create the individual chargers and append them to the final instance
|
||||
dcs = make(utils.DerivedChargers, 0)
|
||||
for runIdx, runId := range runIds {
|
||||
dc, err := utils.NewDerivedCharger(runId, reqTypeFlds[runIdx], directionFlds[runIdx], tenantFlds[runIdx], torFlds[runIdx],
|
||||
acntFlds[runIdx], subjFlds[runIdx], dstFlds[runIdx], sTimeFlds[runIdx], aTimeFlds[runIdx], durFlds[runIdx])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dcs, err = dcs.Append(dc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return dcs, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
@@ -37,3 +37,29 @@ func TestParseRSRFields(t *testing.T) {
|
||||
t.Errorf("Unexpected value of parsed fields")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCfgDerivedCharging(t *testing.T) {
|
||||
eFieldsCfg := []byte(`[derived_charging]
|
||||
run_ids = run1, run2
|
||||
reqtype_fields = test1, test2
|
||||
direction_fields = test1, test2
|
||||
tenant_fields = test1, test2
|
||||
tor_fields = test1, test2
|
||||
account_fields = test1, test2
|
||||
subject_fields = test1, test2
|
||||
destination_fields = test1, test2
|
||||
setup_time_fields = test1, test2
|
||||
answer_time_fields = test1, test2
|
||||
duration_fields = test1, test2
|
||||
`)
|
||||
edcs := utils.DerivedChargers{
|
||||
&utils.DerivedCharger{RunId: "run1", ReqTypeField: "test1", DirectionField: "test1", TenantField: "test1", TorField: "test1",
|
||||
AccountField: "test1", SubjectField: "test1", DestinationField: "test1", SetupTimeField: "test1", AnswerTimeField: "test1", DurationField: "test1"},
|
||||
&utils.DerivedCharger{RunId: "run2", ReqTypeField: "test2", DirectionField: "test2", TenantField: "test2", TorField: "test2",
|
||||
AccountField: "test2", SubjectField: "test2", DestinationField: "test2", SetupTimeField: "test2", AnswerTimeField: "test2", DurationField: "test2"}}
|
||||
if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil {
|
||||
t.Error("Could not parse the config", err.Error())
|
||||
} else if !reflect.DeepEqual(cfg.DerivedChargers, edcs) {
|
||||
t.Errorf("Expecting: %v, received: %v", edcs, cfg.DerivedChargers)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ destination_fields = test # Name of destination fields to be used during additio
|
||||
setup_time_fields = test # Name of setup_time fields to be used during additional sessions control <""|*default|field_name>.
|
||||
answer_time_fields = test # Name of answer_time fields to be used during additional sessions control <""|*default|field_name>.
|
||||
duration_fields = test # Name of duration fields to be used during additional sessions control <""|*default|field_name>.
|
||||
combined_chargers = true # Combine accounts specific derived_chargers with server configured ones <true|false>.
|
||||
|
||||
[history_server]
|
||||
enabled = true # Starts History service: <true|false>.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# CGRateS Configuration file
|
||||
# Real-time Charging System for Telecom & ISP environments
|
||||
# Copyright (C) 2012-2014 ITsysCOM GmbH
|
||||
#
|
||||
# This file contains the default configuration hardcoded into CGRateS.
|
||||
# This is what you get when you load CGRateS with an empty configuration file.
|
||||
# [global] must exist in all files, rest of the configuration is inter-changeable.
|
||||
|
||||
[global]
|
||||
# ratingdb_type = redis # Rating subsystem database: <redis>.
|
||||
@@ -58,7 +58,6 @@
|
||||
# export_dir = /var/log/cgrates/cdrexport/csv # Path where the exported CDRs will be placed
|
||||
# export_template = cgrid,mediation_runid,accid,cdrhost,reqtype,direction,tenant,tor,account,subject,destination,setup_time,answer_time,duration,cost
|
||||
# Exported fields template <""|fld1,fld2|*xml:instance_name>
|
||||
|
||||
[cdrc]
|
||||
# enabled = false # Enable CDR client functionality
|
||||
# cdrs = internal # Address where to reach CDR server. <internal|127.0.0.1:2080>
|
||||
@@ -111,6 +110,7 @@
|
||||
# setup_time_fields = # Name of setup_time fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# answer_time_fields = # Name of answer_time fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# duration_fields = # Name of duration fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# combined_chargers = true # Combine accounts specific derived_chargers with server configured ones <true|false>.
|
||||
|
||||
[history_server]
|
||||
# enabled = false # Starts History service: <true|false>.
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
@@ -51,7 +50,7 @@ type CSVReader struct {
|
||||
ratingPlans map[string]*RatingPlan
|
||||
ratingProfiles map[string]*RatingProfile
|
||||
sharedGroups map[string]*SharedGroup
|
||||
derivedChargers map[string]config.DerivedChargers
|
||||
derivedChargers map[string]utils.DerivedChargers
|
||||
// file names
|
||||
destinationsFn, ratesFn, destinationratesFn, timingsFn, destinationratetimingsFn, ratingprofilesFn,
|
||||
sharedgroupsFn, actionsFn, actiontimingsFn, actiontriggersFn, accountactionsFn, derivedChargersFn string
|
||||
@@ -74,7 +73,7 @@ func NewFileCSVReader(dataStorage RatingStorage, accountingStorage AccountingSto
|
||||
c.ratingPlans = make(map[string]*RatingPlan)
|
||||
c.ratingProfiles = make(map[string]*RatingProfile)
|
||||
c.sharedGroups = make(map[string]*SharedGroup)
|
||||
c.derivedChargers = make(map[string]config.DerivedChargers)
|
||||
c.derivedChargers = make(map[string]utils.DerivedChargers)
|
||||
c.readerFunc = openFileCSVReader
|
||||
c.rpAliases = make(map[string]string)
|
||||
c.accAliases = make(map[string]string)
|
||||
@@ -753,10 +752,10 @@ func (csvr *CSVReader) LoadDerivedChargers() (err error) {
|
||||
defer fp.Close()
|
||||
}
|
||||
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
|
||||
tag := utils.ConcatenatedKey(record[0], record[1], record[2], record[3], record[4])
|
||||
tag := utils.DerivedChargersKey(record[0], record[1], record[2], record[3], record[4])
|
||||
_, found := csvr.derivedChargers[tag]
|
||||
if found {
|
||||
if csvr.derivedChargers[tag], err = csvr.derivedChargers[tag].Append(&config.DerivedCharger{
|
||||
if csvr.derivedChargers[tag], err = csvr.derivedChargers[tag].Append(&utils.DerivedCharger{
|
||||
RunId: ValueOrDefault(record[5], "*default"),
|
||||
ReqTypeField: ValueOrDefault(record[6], "*default"),
|
||||
DirectionField: ValueOrDefault(record[7], "*default"),
|
||||
@@ -775,7 +774,7 @@ func (csvr *CSVReader) LoadDerivedChargers() (err error) {
|
||||
if record[5] == utils.DEFAULT_RUNID {
|
||||
return errors.New("Reserved RunId")
|
||||
}
|
||||
csvr.derivedChargers[tag] = config.DerivedChargers{&config.DerivedCharger{
|
||||
csvr.derivedChargers[tag] = utils.DerivedChargers{&utils.DerivedCharger{
|
||||
RunId: ValueOrDefault(record[5], "*default"),
|
||||
ReqTypeField: ValueOrDefault(record[6], "*default"),
|
||||
DirectionField: ValueOrDefault(record[7], "*default"),
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
@@ -834,10 +833,10 @@ func TestLoadDerivedChargers(t *testing.T) {
|
||||
if len(csvr.derivedChargers) != 2 {
|
||||
t.Error("Failed to load derivedChargers: ", csvr.derivedChargers)
|
||||
}
|
||||
expCharger1 := config.DerivedChargers{
|
||||
&config.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
expCharger1 := utils.DerivedChargers{
|
||||
&utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
|
||||
&config.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
&utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
|
||||
}
|
||||
keyCharger1 := utils.ConcatenatedKey("cgrates.org", "call", "*out", "dan", "dan")
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
@@ -48,7 +47,7 @@ type DbReader struct {
|
||||
ratingPlans map[string]*RatingPlan
|
||||
ratingProfiles map[string]*RatingProfile
|
||||
sharedGroups map[string]*SharedGroup
|
||||
derivedChargers map[string]config.DerivedChargers
|
||||
derivedChargers map[string]utils.DerivedChargers
|
||||
}
|
||||
|
||||
func NewDbReader(storDB LoadStorage, ratingDb RatingStorage, accountDb AccountingStorage, tpid string) *DbReader {
|
||||
@@ -66,7 +65,7 @@ func NewDbReader(storDB LoadStorage, ratingDb RatingStorage, accountDb Accountin
|
||||
c.rpAliases = make(map[string]string)
|
||||
c.accAliases = make(map[string]string)
|
||||
c.accountActions = make(map[string]*Account)
|
||||
c.derivedChargers = make(map[string]config.DerivedChargers)
|
||||
c.derivedChargers = make(map[string]utils.DerivedChargers)
|
||||
return c
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
@@ -28,6 +28,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/balancer2go"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
type Responder struct {
|
||||
@@ -114,6 +116,17 @@ func (rs *Responder) GetMaxSessionTime(arg CallDescriptor, reply *float64) (err
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) DerivedChargers(attrs utils.AttrDerivedChargers, dcs *utils.DerivedChargers) error {
|
||||
// ToDo: Make it work with balancer if needed
|
||||
|
||||
if dcsH, err := HandleGetDerivedChargers(accountingStorage, config.CgrConfig(), attrs); err != nil {
|
||||
return err
|
||||
} else if dcsH != nil {
|
||||
*dcs = dcsH
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rs *Responder) FlushCache(arg CallDescriptor, reply *float64) (err error) {
|
||||
if rs.Bal != nil {
|
||||
*reply, err = rs.callMethod(&arg, "Responder.FlushCache")
|
||||
@@ -319,6 +332,7 @@ type Connector interface {
|
||||
MaxDebit(CallDescriptor, *CallCost) error
|
||||
RefundIncrements(CallDescriptor, *float64) error
|
||||
GetMaxSessionTime(CallDescriptor, *float64) error
|
||||
DerivedChargers(utils.AttrDerivedChargers, utils.DerivedChargers) error
|
||||
}
|
||||
|
||||
type RPCClientConnector struct {
|
||||
@@ -344,3 +358,7 @@ func (rcc *RPCClientConnector) RefundIncrements(cd CallDescriptor, resp *float64
|
||||
func (rcc *RPCClientConnector) GetMaxSessionTime(cd CallDescriptor, resp *float64) error {
|
||||
return rcc.Client.Call("Responder.GetMaxSessionTime", cd, resp)
|
||||
}
|
||||
|
||||
func (rcc *RPCClientConnector) DerivedChargers(attrs utils.AttrDerivedChargers, dcs utils.DerivedChargers) error {
|
||||
return rcc.Client.Call("ApierV1.DerivedChargers", attrs, dcs)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/ugorji/go/codec"
|
||||
"labix.org/v2/mgo/bson"
|
||||
@@ -102,8 +101,8 @@ type AccountingStorage interface {
|
||||
GetActionTimings(string) (ActionPlan, error)
|
||||
SetActionTimings(string, ActionPlan) error
|
||||
GetAllActionTimings() (map[string]ActionPlan, error)
|
||||
GetDerivedChargers(string, bool) (config.DerivedChargers, error)
|
||||
SetDerivedChargers(string, config.DerivedChargers) error
|
||||
GetDerivedChargers(string, bool) (utils.DerivedChargers, error)
|
||||
SetDerivedChargers(string, utils.DerivedChargers) error
|
||||
}
|
||||
|
||||
type CdrStorage interface {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriems World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/cache2go"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
@@ -438,10 +437,10 @@ func (ms *MapStorage) GetAllActionTimings() (ats map[string]ActionPlan, err erro
|
||||
return
|
||||
}
|
||||
|
||||
func (ms *MapStorage) GetDerivedChargers(key string, checkDb bool) (dcs config.DerivedChargers, err error) {
|
||||
func (ms *MapStorage) GetDerivedChargers(key string, checkDb bool) (dcs utils.DerivedChargers, err error) {
|
||||
key = DERIVEDCHARGERS_PREFIX + key
|
||||
if x, err := cache2go.GetCached(key); err == nil {
|
||||
return x.(config.DerivedChargers), nil
|
||||
return x.(utils.DerivedChargers), nil
|
||||
}
|
||||
if !checkDb {
|
||||
return nil, errors.New(utils.ERR_NOT_FOUND)
|
||||
@@ -455,7 +454,7 @@ func (ms *MapStorage) GetDerivedChargers(key string, checkDb bool) (dcs config.D
|
||||
return
|
||||
}
|
||||
|
||||
func (ms *MapStorage) SetDerivedChargers(key string, dcs config.DerivedChargers) error {
|
||||
func (ms *MapStorage) SetDerivedChargers(key string, dcs utils.DerivedChargers) error {
|
||||
result, err := ms.ms.Marshal(dcs)
|
||||
ms.dict[DERIVEDCHARGERS_PREFIX+key] = result
|
||||
return err
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cgrates/cgrates/cache2go"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/hoisie/redis"
|
||||
|
||||
@@ -544,10 +543,10 @@ func (rs *RedisStorage) GetAllActionTimings() (ats map[string]ActionPlan, err er
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) GetDerivedChargers(key string, checkDb bool) (dcs config.DerivedChargers, err error) {
|
||||
func (rs *RedisStorage) GetDerivedChargers(key string, checkDb bool) (dcs utils.DerivedChargers, err error) {
|
||||
key = DERIVEDCHARGERS_PREFIX + key
|
||||
if x, err := cache2go.GetCached(key); err == nil {
|
||||
return x.(config.DerivedChargers), nil
|
||||
return x.(utils.DerivedChargers), nil
|
||||
}
|
||||
if !checkDb {
|
||||
return nil, errors.New(utils.ERR_NOT_FOUND)
|
||||
@@ -560,7 +559,7 @@ func (rs *RedisStorage) GetDerivedChargers(key string, checkDb bool) (dcs config
|
||||
return dcs, err
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) SetDerivedChargers(key string, dcs config.DerivedChargers) (err error) {
|
||||
func (rs *RedisStorage) SetDerivedChargers(key string, dcs utils.DerivedChargers) (err error) {
|
||||
if len(dcs) == 0 {
|
||||
_, err = rs.db.Del(DERIVEDCHARGERS_PREFIX + key)
|
||||
return err
|
||||
|
||||
@@ -56,10 +56,10 @@ func TestSetGetDerivedCharges(t *testing.T) {
|
||||
return
|
||||
}
|
||||
keyCharger1 := utils.ConcatenatedKey("cgrates.org", "call", "*out", "dan", "dan")
|
||||
charger1 := config.DerivedChargers{
|
||||
&config.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
charger1 := utils.DerivedChargers{
|
||||
&utils.DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
|
||||
&config.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
&utils.DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", TorField: "*default",
|
||||
AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", DurationField: "*default"},
|
||||
}
|
||||
if err := rds.SetDerivedChargers(keyCharger1, charger1); err != nil {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 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
|
||||
|
||||
@@ -377,3 +377,7 @@ type AttrLoadTpFromFolder struct {
|
||||
type AttrGetDestination struct {
|
||||
Id string
|
||||
}
|
||||
|
||||
type AttrDerivedChargers struct {
|
||||
Tenant, Tor, Direction, Account, Subject string
|
||||
}
|
||||
|
||||
136
utils/derivedchargers.go
Normal file
136
utils/derivedchargers.go
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can Storagetribute 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 WITH*out 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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Wraps regexp compiling in case of rsr fields
|
||||
func NewDerivedCharger(runId, reqTypeFld, dirFld, tenantFld, totFld, acntFld, subjFld, dstFld, sTimeFld, aTimeFld, durFld string) (dc *DerivedCharger, err error) {
|
||||
if len(runId) == 0 {
|
||||
return nil, errors.New("Empty run id field")
|
||||
}
|
||||
dc = &DerivedCharger{RunId: runId}
|
||||
dc.ReqTypeField = reqTypeFld
|
||||
if strings.HasPrefix(dc.ReqTypeField, REGEXP_PREFIX) {
|
||||
if dc.rsrReqTypeField, err = NewRSRField(dc.ReqTypeField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.DirectionField = dirFld
|
||||
if strings.HasPrefix(dc.DirectionField, REGEXP_PREFIX) {
|
||||
if dc.rsrDirectionField, err = NewRSRField(dc.DirectionField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.TenantField = tenantFld
|
||||
if strings.HasPrefix(dc.TenantField, REGEXP_PREFIX) {
|
||||
if dc.rsrTenantField, err = NewRSRField(dc.TenantField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.TorField = totFld
|
||||
if strings.HasPrefix(dc.TorField, REGEXP_PREFIX) {
|
||||
if dc.rsrTorField, err = NewRSRField(dc.TorField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.AccountField = acntFld
|
||||
if strings.HasPrefix(dc.AccountField, REGEXP_PREFIX) {
|
||||
if dc.rsrAccountField, err = NewRSRField(dc.AccountField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.SubjectField = subjFld
|
||||
if strings.HasPrefix(dc.SubjectField, REGEXP_PREFIX) {
|
||||
if dc.rsrSubjectField, err = NewRSRField(dc.SubjectField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.DestinationField = dstFld
|
||||
if strings.HasPrefix(dc.DestinationField, REGEXP_PREFIX) {
|
||||
if dc.rsrDestinationField, err = NewRSRField(dc.DestinationField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.SetupTimeField = sTimeFld
|
||||
if strings.HasPrefix(dc.SetupTimeField, REGEXP_PREFIX) {
|
||||
if dc.rsrSetupTimeField, err = NewRSRField(dc.SetupTimeField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.AnswerTimeField = aTimeFld
|
||||
if strings.HasPrefix(dc.AnswerTimeField, REGEXP_PREFIX) {
|
||||
if dc.rsrAnswerTimeField, err = NewRSRField(dc.AnswerTimeField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.DurationField = durFld
|
||||
if strings.HasPrefix(dc.DurationField, REGEXP_PREFIX) {
|
||||
if dc.rsrDurationField, err = NewRSRField(dc.DurationField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return dc, nil
|
||||
}
|
||||
|
||||
type DerivedCharger struct {
|
||||
RunId string // Unique runId in the chain
|
||||
ReqTypeField string // Field containing request type info, number in case of csv source, '^' as prefix in case of static values
|
||||
DirectionField string // Field containing direction info
|
||||
TenantField string // Field containing tenant info
|
||||
TorField string // Field containing tor info
|
||||
AccountField string // Field containing account information
|
||||
SubjectField string // Field containing subject information
|
||||
DestinationField string // Field containing destination information
|
||||
SetupTimeField string // Field containing setup time information
|
||||
AnswerTimeField string // Field containing answer time information
|
||||
DurationField string // Field containing duration information
|
||||
rsrReqTypeField *RSRField // Storage for compiled Regexp in case of RSRFields
|
||||
rsrDirectionField *RSRField
|
||||
rsrTenantField *RSRField
|
||||
rsrTorField *RSRField
|
||||
rsrAccountField *RSRField
|
||||
rsrSubjectField *RSRField
|
||||
rsrDestinationField *RSRField
|
||||
rsrSetupTimeField *RSRField
|
||||
rsrAnswerTimeField *RSRField
|
||||
rsrDurationField *RSRField
|
||||
}
|
||||
|
||||
func DerivedChargersKey(tenant, tor, direction, account, subject string) string {
|
||||
return ConcatenatedKey(tenant, tor, direction, account, subject)
|
||||
}
|
||||
|
||||
type DerivedChargers []*DerivedCharger
|
||||
|
||||
// Precheck that RunId is unique
|
||||
func (dcs DerivedChargers) Append(dc *DerivedCharger) (DerivedChargers, error) {
|
||||
if dc.RunId == DEFAULT_RUNID {
|
||||
return nil, errors.New("Reserved RunId")
|
||||
}
|
||||
for _, dcLocal := range dcs {
|
||||
if dcLocal.RunId == dc.RunId {
|
||||
return nil, errors.New("Duplicated RunId")
|
||||
}
|
||||
}
|
||||
return append(dcs, dc), nil
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Rating system for Telecom Environments
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2014 ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can Storagetribute it and/or modify
|
||||
@@ -16,10 +16,9 @@ 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 config
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
@@ -27,7 +26,7 @@ import (
|
||||
func TestAppendDerivedChargers(t *testing.T) {
|
||||
var err error
|
||||
dcs := make(DerivedChargers, 0)
|
||||
if _, err := dcs.Append(&DerivedCharger{RunId: utils.DEFAULT_RUNID}); err == nil {
|
||||
if _, err := dcs.Append(&DerivedCharger{RunId: DEFAULT_RUNID}); err == nil {
|
||||
t.Error("Failed to detect using of the default runid")
|
||||
}
|
||||
if dcs, err = dcs.Append(&DerivedCharger{RunId: "FIRST_RUNID"}); err != nil {
|
||||
@@ -78,16 +77,16 @@ func TestNewDerivedCharger(t *testing.T) {
|
||||
AnswerTimeField: "~answertime2:s/sip:(.+)/$1/",
|
||||
DurationField: "~duration2:s/sip:(.+)/$1/",
|
||||
}
|
||||
edc2.rsrReqTypeField, _ = utils.NewRSRField("~reqtype2:s/sip:(.+)/$1/")
|
||||
edc2.rsrDirectionField, _ = utils.NewRSRField("~direction2:s/sip:(.+)/$1/")
|
||||
edc2.rsrTenantField, _ = utils.NewRSRField("~tenant2:s/sip:(.+)/$1/")
|
||||
edc2.rsrTorField, _ = utils.NewRSRField("~tor2:s/sip:(.+)/$1/")
|
||||
edc2.rsrAccountField, _ = utils.NewRSRField("~account2:s/sip:(.+)/$1/")
|
||||
edc2.rsrSubjectField, _ = utils.NewRSRField("~subject2:s/sip:(.+)/$1/")
|
||||
edc2.rsrDestinationField, _ = utils.NewRSRField("~destination2:s/sip:(.+)/$1/")
|
||||
edc2.rsrSetupTimeField, _ = utils.NewRSRField("~setuptime2:s/sip:(.+)/$1/")
|
||||
edc2.rsrAnswerTimeField, _ = utils.NewRSRField("~answertime2:s/sip:(.+)/$1/")
|
||||
edc2.rsrDurationField, _ = utils.NewRSRField("~duration2:s/sip:(.+)/$1/")
|
||||
edc2.rsrReqTypeField, _ = NewRSRField("~reqtype2:s/sip:(.+)/$1/")
|
||||
edc2.rsrDirectionField, _ = NewRSRField("~direction2:s/sip:(.+)/$1/")
|
||||
edc2.rsrTenantField, _ = NewRSRField("~tenant2:s/sip:(.+)/$1/")
|
||||
edc2.rsrTorField, _ = NewRSRField("~tor2:s/sip:(.+)/$1/")
|
||||
edc2.rsrAccountField, _ = NewRSRField("~account2:s/sip:(.+)/$1/")
|
||||
edc2.rsrSubjectField, _ = NewRSRField("~subject2:s/sip:(.+)/$1/")
|
||||
edc2.rsrDestinationField, _ = NewRSRField("~destination2:s/sip:(.+)/$1/")
|
||||
edc2.rsrSetupTimeField, _ = NewRSRField("~setuptime2:s/sip:(.+)/$1/")
|
||||
edc2.rsrAnswerTimeField, _ = NewRSRField("~answertime2:s/sip:(.+)/$1/")
|
||||
edc2.rsrDurationField, _ = NewRSRField("~duration2:s/sip:(.+)/$1/")
|
||||
if dc2, err := NewDerivedCharger("test2",
|
||||
"~reqtype2:s/sip:(.+)/$1/",
|
||||
"~direction2:s/sip:(.+)/$1/",
|
||||
@@ -105,28 +104,8 @@ func TestNewDerivedCharger(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCfgDerivedCharging(t *testing.T) {
|
||||
eFieldsCfg := []byte(`[derived_charging]
|
||||
run_ids = run1, run2
|
||||
reqtype_fields = test1, test2
|
||||
direction_fields = test1, test2
|
||||
tenant_fields = test1, test2
|
||||
tor_fields = test1, test2
|
||||
account_fields = test1, test2
|
||||
subject_fields = test1, test2
|
||||
destination_fields = test1, test2
|
||||
setup_time_fields = test1, test2
|
||||
answer_time_fields = test1, test2
|
||||
duration_fields = test1, test2
|
||||
`)
|
||||
edcs := DerivedChargers{
|
||||
&DerivedCharger{RunId: "run1", ReqTypeField: "test1", DirectionField: "test1", TenantField: "test1", TorField: "test1",
|
||||
AccountField: "test1", SubjectField: "test1", DestinationField: "test1", SetupTimeField: "test1", AnswerTimeField: "test1", DurationField: "test1"},
|
||||
&DerivedCharger{RunId: "run2", ReqTypeField: "test2", DirectionField: "test2", TenantField: "test2", TorField: "test2",
|
||||
AccountField: "test2", SubjectField: "test2", DestinationField: "test2", SetupTimeField: "test2", AnswerTimeField: "test2", DurationField: "test2"}}
|
||||
if cfg, err := NewCGRConfigFromBytes(eFieldsCfg); err != nil {
|
||||
t.Error("Could not parse the config", err.Error())
|
||||
} else if !reflect.DeepEqual(cfg.DerivedChargers, edcs) {
|
||||
t.Errorf("Expecting: %v, received: %v", edcs, cfg.DerivedChargers)
|
||||
func TestDerivedChargersKey(t *testing.T) {
|
||||
if dcKey := DerivedChargersKey("cgrates.org", "call", "*out", "dan", "dan"); dcKey != "cgrates.org:call:*out:dan:dan" {
|
||||
t.Error("Unexpected derived chargers key: ", dcKey)
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,9 @@ func (rsr *ReSearchReplace) Process(source string) string {
|
||||
}
|
||||
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
|
||||
}
|
||||
res = rsr.SearchRegexp.ExpandString(res, rsr.ReplaceTemplate, source, match)
|
||||
return string(res)
|
||||
}
|
||||
|
||||
@@ -49,3 +49,13 @@ func TestProcessReSearchReplace3(t *testing.T) { //"MatchedDestId":"CST_31800_DE
|
||||
t.Error("Unexpected output from SearchReplace: ", outStr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessReSearchReplace4(t *testing.T) {
|
||||
rsr := &ReSearchReplace{regexp.MustCompile(`^\+49(\d+)`), "0$1"}
|
||||
if outStr := rsr.Process("+4986517174963"); outStr != "086517174963" {
|
||||
t.Error("Unexpected output from SearchReplace: ", outStr)
|
||||
}
|
||||
if outStr := rsr.Process("+186517174963"); outStr != "+186517174963" {
|
||||
t.Error("Unexpected output from SearchReplace: ", outStr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,9 @@ func TestFormatCost(t *testing.T) {
|
||||
if cdr.FormatCost(2, 0) != "101" {
|
||||
t.Error("Unexpected format of the cost: ", cdr.FormatCost(2, 0))
|
||||
}
|
||||
if cdr.FormatCost(1, 0) != "10" {
|
||||
t.Error("Unexpected format of the cost: ", cdr.FormatCost(1, 0))
|
||||
}
|
||||
if cdr.FormatCost(2, 3) != "101.001" {
|
||||
t.Error("Unexpected format of the cost: ", cdr.FormatCost(2, 3))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user