mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Refactoring configuration for DerivedCharging
This commit is contained in:
177
config/config.go
177
config/config.go
@@ -123,17 +123,6 @@ type CGRConfig struct {
|
||||
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
|
||||
SMRunIds []string // Identifiers of additional sessions control.
|
||||
SMReqTypeFields []string // Name of request type fields to be used during additional sessions control <""|*default|field_name>.
|
||||
SMDirectionFields []string // Name of direction fields to be used during additional sessions control <""|*default|field_name>.
|
||||
SMTenantFields []string // Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
|
||||
SMTORFields []string // Name of tor fields to be used during additional sessions control <""|*default|field_name>.
|
||||
SMAccountFields []string // Name of account fields to be used during additional sessions control <""|*default|field_name>.
|
||||
SMSubjectFields []string // Name of fields to be used during additional sessions control <""|*default|field_name>.
|
||||
SMDestFields []string // Name of destination fields to be used during additional sessions control <""|*default|field_name>.
|
||||
SMSetupTimeFields []string // Name of setup_time fields to be used during additional sessions control <""|*default|field_name>.
|
||||
SMAnswerTimeFields []string // Name of answer_time fields to be used during additional sessions control <""|*default|field_name>.
|
||||
SMDurationFields []string // Name of duration fields to be used during additional sessions control <""|*default|field_name>.
|
||||
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.
|
||||
@@ -148,7 +137,7 @@ type CGRConfig struct {
|
||||
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 pseudosessions which will be executed in case of no particular ones defined per account
|
||||
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
|
||||
@@ -228,17 +217,6 @@ func (self *CGRConfig) setDefaults() error {
|
||||
self.MediatorEnabled = false
|
||||
self.MediatorRater = "internal"
|
||||
self.MediatorRaterReconnects = 3
|
||||
self.MediatorRunIds = []string{}
|
||||
self.MediatorSubjectFields = []string{}
|
||||
self.MediatorReqTypeFields = []string{}
|
||||
self.MediatorDirectionFields = []string{}
|
||||
self.MediatorTenantFields = []string{}
|
||||
self.MediatorTORFields = []string{}
|
||||
self.MediatorAccountFields = []string{}
|
||||
self.MediatorDestFields = []string{}
|
||||
self.MediatorSetupTimeFields = []string{}
|
||||
self.MediatorAnswerTimeFields = []string{}
|
||||
self.MediatorDurationFields = []string{}
|
||||
self.DerivedChargers = make(DerivedChargers, 0)
|
||||
self.SMEnabled = false
|
||||
self.SMSwitchType = FS
|
||||
@@ -246,17 +224,6 @@ func (self *CGRConfig) setDefaults() error {
|
||||
self.SMRaterReconnects = 3
|
||||
self.SMDebitInterval = 10
|
||||
self.SMMaxCallDuration = time.Duration(3) * time.Hour
|
||||
self.SMRunIds = []string{}
|
||||
self.SMReqTypeFields = []string{}
|
||||
self.SMDirectionFields = []string{}
|
||||
self.SMTenantFields = []string{}
|
||||
self.SMTORFields = []string{}
|
||||
self.SMAccountFields = []string{}
|
||||
self.SMSubjectFields = []string{}
|
||||
self.SMDestFields = []string{}
|
||||
self.SMSetupTimeFields = []string{}
|
||||
self.SMAnswerTimeFields = []string{}
|
||||
self.SMDurationFields = []string{}
|
||||
self.FreeswitchServer = "127.0.0.1:8021"
|
||||
self.FreeswitchPass = "ClueCon"
|
||||
self.FreeswitchReconnects = 5
|
||||
@@ -298,32 +265,6 @@ func (self *CGRConfig) checkConfigSanity() error {
|
||||
return errors.New("Need XmlTemplate for fixed_width cdr export")
|
||||
}
|
||||
}
|
||||
// SessionManager should have same fields config length for session emulation
|
||||
if len(self.SMReqTypeFields) != len(self.SMRunIds) ||
|
||||
len(self.SMDirectionFields) != len(self.SMRunIds) ||
|
||||
len(self.SMTenantFields) != len(self.SMRunIds) ||
|
||||
len(self.SMTORFields) != len(self.SMRunIds) ||
|
||||
len(self.SMAccountFields) != len(self.SMRunIds) ||
|
||||
len(self.SMSubjectFields) != len(self.SMRunIds) ||
|
||||
len(self.SMDestFields) != len(self.SMRunIds) ||
|
||||
len(self.SMSetupTimeFields) != len(self.SMRunIds) ||
|
||||
len(self.SMAnswerTimeFields) != len(self.SMRunIds) ||
|
||||
len(self.SMDurationFields) != len(self.SMRunIds) {
|
||||
return errors.New("<ConfigSanity> Inconsistent fields length for SessionManager session emulation")
|
||||
}
|
||||
// Mediator needs to have consistent extra fields definition
|
||||
if len(self.MediatorReqTypeFields) != len(self.MediatorRunIds) ||
|
||||
len(self.MediatorDirectionFields) != len(self.MediatorRunIds) ||
|
||||
len(self.MediatorTenantFields) != len(self.MediatorRunIds) ||
|
||||
len(self.MediatorTORFields) != len(self.MediatorRunIds) ||
|
||||
len(self.MediatorAccountFields) != len(self.MediatorRunIds) ||
|
||||
len(self.MediatorSubjectFields) != len(self.MediatorRunIds) ||
|
||||
len(self.MediatorDestFields) != len(self.MediatorRunIds) ||
|
||||
len(self.MediatorSetupTimeFields) != len(self.MediatorRunIds) ||
|
||||
len(self.MediatorAnswerTimeFields) != len(self.MediatorRunIds) ||
|
||||
len(self.MediatorDurationFields) != len(self.MediatorRunIds) {
|
||||
return errors.New("<ConfigSanity> Inconsistent fields length for Mediator extra fields")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -585,7 +526,8 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
cfg.CdrcDurationField, _ = c.GetString("cdrc", "duration_field")
|
||||
}
|
||||
if hasOpt = c.HasOption("cdrc", "extra_fields"); hasOpt {
|
||||
if cfg.CdrcExtraFields, err = ConfigSlice(c, "cdrc", "extra_fields"); err != nil {
|
||||
eFldsStr, _ := c.GetString("cdrc", "extra_fields")
|
||||
if cfg.CdrcExtraFields, err = ConfigSlice(eFldsStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -598,61 +540,6 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
if hasOpt = c.HasOption("mediator", "rater_reconnects"); hasOpt {
|
||||
cfg.MediatorRaterReconnects, _ = c.GetInt("mediator", "rater_reconnects")
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "run_ids"); hasOpt {
|
||||
if cfg.MediatorRunIds, err = ConfigSlice(c, "mediator", "run_ids"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "subject_fields"); hasOpt {
|
||||
if cfg.MediatorSubjectFields, err = ConfigSlice(c, "mediator", "subject_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "reqtype_fields"); hasOpt {
|
||||
if cfg.MediatorReqTypeFields, err = ConfigSlice(c, "mediator", "reqtype_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "direction_fields"); hasOpt {
|
||||
if cfg.MediatorDirectionFields, err = ConfigSlice(c, "mediator", "direction_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "tenant_fields"); hasOpt {
|
||||
if cfg.MediatorTenantFields, err = ConfigSlice(c, "mediator", "tenant_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "tor_fields"); hasOpt {
|
||||
if cfg.MediatorTORFields, err = ConfigSlice(c, "mediator", "tor_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "account_fields"); hasOpt {
|
||||
if cfg.MediatorAccountFields, err = ConfigSlice(c, "mediator", "account_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "destination_fields"); hasOpt {
|
||||
if cfg.MediatorDestFields, err = ConfigSlice(c, "mediator", "destination_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "setup_time_fields"); hasOpt {
|
||||
if cfg.MediatorSetupTimeFields, err = ConfigSlice(c, "mediator", "setup_time_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "answer_time_fields"); hasOpt {
|
||||
if cfg.MediatorAnswerTimeFields, err = ConfigSlice(c, "mediator", "answer_time_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "duration_fields"); hasOpt {
|
||||
if cfg.MediatorDurationFields, err = ConfigSlice(c, "mediator", "duration_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "enabled"); hasOpt {
|
||||
cfg.SMEnabled, _ = c.GetBool("session_manager", "enabled")
|
||||
}
|
||||
@@ -674,61 +561,6 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "run_ids"); hasOpt {
|
||||
if cfg.SMRunIds, err = ConfigSlice(c, "session_manager", "run_ids"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "reqtype_fields"); hasOpt {
|
||||
if cfg.SMReqTypeFields, err = ConfigSlice(c, "session_manager", "reqtype_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "direction_fields"); hasOpt {
|
||||
if cfg.SMDirectionFields, err = ConfigSlice(c, "session_manager", "direction_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "tenant_fields"); hasOpt {
|
||||
if cfg.SMTenantFields, err = ConfigSlice(c, "session_manager", "tenant_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "tor_fields"); hasOpt {
|
||||
if cfg.SMTORFields, err = ConfigSlice(c, "session_manager", "tor_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "account_fields"); hasOpt {
|
||||
if cfg.SMAccountFields, err = ConfigSlice(c, "session_manager", "account_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "subject_fields"); hasOpt {
|
||||
if cfg.SMSubjectFields, err = ConfigSlice(c, "session_manager", "subject_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "destination_fields"); hasOpt {
|
||||
if cfg.SMDestFields, err = ConfigSlice(c, "session_manager", "destination_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "setup_time_fields"); hasOpt {
|
||||
if cfg.SMSetupTimeFields, err = ConfigSlice(c, "session_manager", "setup_time_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "answer_time_fields"); hasOpt {
|
||||
if cfg.SMAnswerTimeFields, err = ConfigSlice(c, "session_manager", "answer_time_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "duration_fields"); hasOpt {
|
||||
if cfg.SMDurationFields, err = ConfigSlice(c, "session_manager", "duration_fields"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("freeswitch", "server"); hasOpt {
|
||||
cfg.FreeswitchServer, _ = c.GetString("freeswitch", "server")
|
||||
}
|
||||
@@ -738,6 +570,9 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
if hasOpt = c.HasOption("freeswitch", "reconnects"); hasOpt {
|
||||
cfg.FreeswitchReconnects, _ = c.GetInt("freeswitch", "reconnects")
|
||||
}
|
||||
if cfg.DerivedChargers, err = ParseCfgDerivedCharging(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hasOpt = c.HasOption("history_agent", "enabled"); hasOpt {
|
||||
cfg.HistoryAgentEnabled, _ = c.GetBool("history_agent", "enabled")
|
||||
}
|
||||
|
||||
@@ -110,38 +110,16 @@ func TestDefaults(t *testing.T) {
|
||||
eCfg.MediatorEnabled = false
|
||||
eCfg.MediatorRater = "internal"
|
||||
eCfg.MediatorRaterReconnects = 3
|
||||
eCfg.MediatorRunIds = []string{}
|
||||
eCfg.MediatorSubjectFields = []string{}
|
||||
eCfg.MediatorReqTypeFields = []string{}
|
||||
eCfg.MediatorDirectionFields = []string{}
|
||||
eCfg.MediatorTenantFields = []string{}
|
||||
eCfg.MediatorTORFields = []string{}
|
||||
eCfg.MediatorAccountFields = []string{}
|
||||
eCfg.MediatorDestFields = []string{}
|
||||
eCfg.MediatorSetupTimeFields = []string{}
|
||||
eCfg.MediatorAnswerTimeFields = []string{}
|
||||
eCfg.DerivedChargers = make(DerivedChargers, 0)
|
||||
eCfg.MediatorDurationFields = []string{}
|
||||
eCfg.SMEnabled = false
|
||||
eCfg.SMSwitchType = FS
|
||||
eCfg.SMRater = "internal"
|
||||
eCfg.SMRaterReconnects = 3
|
||||
eCfg.SMDebitInterval = 10
|
||||
eCfg.SMMaxCallDuration = time.Duration(3) * time.Hour
|
||||
eCfg.SMRunIds = []string{}
|
||||
eCfg.SMReqTypeFields = []string{}
|
||||
eCfg.SMDirectionFields = []string{}
|
||||
eCfg.SMTenantFields = []string{}
|
||||
eCfg.SMTORFields = []string{}
|
||||
eCfg.SMAccountFields = []string{}
|
||||
eCfg.SMSubjectFields = []string{}
|
||||
eCfg.SMDestFields = []string{}
|
||||
eCfg.SMSetupTimeFields = []string{}
|
||||
eCfg.SMAnswerTimeFields = []string{}
|
||||
eCfg.SMDurationFields = []string{}
|
||||
eCfg.FreeswitchServer = "127.0.0.1:8021"
|
||||
eCfg.FreeswitchPass = "ClueCon"
|
||||
eCfg.FreeswitchReconnects = 5
|
||||
eCfg.DerivedChargers = make(DerivedChargers, 0)
|
||||
eCfg.HistoryAgentEnabled = false
|
||||
eCfg.HistoryServer = "internal"
|
||||
eCfg.HistoryServerEnabled = false
|
||||
@@ -184,10 +162,6 @@ func TestSanityCheck(t *testing.T) {
|
||||
if err := cfg.checkConfigSanity(); err != nil {
|
||||
t.Error("Invalid defaults: ", err)
|
||||
}
|
||||
cfg.SMSubjectFields = []string{"sample1", "sample2", "sample3"}
|
||||
if err := cfg.checkConfigSanity(); err == nil {
|
||||
t.Error("Failed to detect config insanity")
|
||||
}
|
||||
cfg = &CGRConfig{}
|
||||
cfg.CdreCdrFormat = utils.CDRE_FIXED_WIDTH
|
||||
if err := cfg.checkConfigSanity(); err == nil {
|
||||
@@ -269,37 +243,17 @@ func TestConfigFromFile(t *testing.T) {
|
||||
eCfg.MediatorEnabled = true
|
||||
eCfg.MediatorRater = "test"
|
||||
eCfg.MediatorRaterReconnects = 99
|
||||
eCfg.MediatorRunIds = []string{"test"}
|
||||
eCfg.MediatorSubjectFields = []string{"test"}
|
||||
eCfg.MediatorReqTypeFields = []string{"test"}
|
||||
eCfg.MediatorDirectionFields = []string{"test"}
|
||||
eCfg.MediatorTenantFields = []string{"test"}
|
||||
eCfg.MediatorTORFields = []string{"test"}
|
||||
eCfg.MediatorAccountFields = []string{"test"}
|
||||
eCfg.MediatorDestFields = []string{"test"}
|
||||
eCfg.MediatorSetupTimeFields = []string{"test"}
|
||||
eCfg.MediatorAnswerTimeFields = []string{"test"}
|
||||
eCfg.MediatorDurationFields = []string{"test"}
|
||||
eCfg.SMEnabled = true
|
||||
eCfg.SMSwitchType = "test"
|
||||
eCfg.SMRater = "test"
|
||||
eCfg.SMRaterReconnects = 99
|
||||
eCfg.SMDebitInterval = 99
|
||||
eCfg.SMMaxCallDuration = time.Duration(99) * time.Second
|
||||
eCfg.SMRunIds = []string{"test"}
|
||||
eCfg.SMReqTypeFields = []string{"test"}
|
||||
eCfg.SMDirectionFields = []string{"test"}
|
||||
eCfg.SMTenantFields = []string{"test"}
|
||||
eCfg.SMTORFields = []string{"test"}
|
||||
eCfg.SMAccountFields = []string{"test"}
|
||||
eCfg.SMSubjectFields = []string{"test"}
|
||||
eCfg.SMDestFields = []string{"test"}
|
||||
eCfg.SMSetupTimeFields = []string{"test"}
|
||||
eCfg.SMAnswerTimeFields = []string{"test"}
|
||||
eCfg.SMDurationFields = []string{"test"}
|
||||
eCfg.FreeswitchServer = "test"
|
||||
eCfg.FreeswitchPass = "test"
|
||||
eCfg.FreeswitchReconnects = 99
|
||||
eCfg.DerivedChargers = DerivedChargers{&DerivedCharger{RunId: "test", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
|
||||
TorField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", DurationField: "test"}}
|
||||
eCfg.HistoryAgentEnabled = true
|
||||
eCfg.HistoryServer = "test"
|
||||
eCfg.HistoryServerEnabled = true
|
||||
|
||||
@@ -19,22 +19,103 @@ 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
|
||||
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
|
||||
@@ -51,3 +132,78 @@ func (dcs DerivedChargers) Append(dc *DerivedCharger) (DerivedChargers, error) {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package config
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -43,3 +44,89 @@ func TestAppendDerivedChargers(t *testing.T) {
|
||||
t.Error("Failed to detect duplicate runid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDerivedCharger(t *testing.T) {
|
||||
edc1 := &DerivedCharger{
|
||||
RunId: "test1",
|
||||
ReqTypeField: "reqtype1",
|
||||
DirectionField: "direction1",
|
||||
TenantField: "tenant1",
|
||||
TorField: "tor1",
|
||||
AccountField: "account1",
|
||||
SubjectField: "subject1",
|
||||
DestinationField: "destination1",
|
||||
SetupTimeField: "setuptime1",
|
||||
AnswerTimeField: "answertime1",
|
||||
DurationField: "duration1",
|
||||
}
|
||||
if dc1, err := NewDerivedCharger("test1", "reqtype1", "direction1", "tenant1", "tor1", "account1", "subject1", "destination1",
|
||||
"setuptime1", "answertime1", "duration1"); err != nil {
|
||||
t.Error("Unexpected error", err.Error)
|
||||
} else if !reflect.DeepEqual(edc1, dc1) {
|
||||
t.Errorf("Expecting: %v, received: %v", edc1, dc1)
|
||||
}
|
||||
edc2 := &DerivedCharger{
|
||||
RunId: "test2",
|
||||
ReqTypeField: "~reqtype2:s/sip:(.+)/$1/",
|
||||
DirectionField: "~direction2:s/sip:(.+)/$1/",
|
||||
TenantField: "~tenant2:s/sip:(.+)/$1/",
|
||||
TorField: "~tor2:s/sip:(.+)/$1/",
|
||||
AccountField: "~account2:s/sip:(.+)/$1/",
|
||||
SubjectField: "~subject2:s/sip:(.+)/$1/",
|
||||
DestinationField: "~destination2:s/sip:(.+)/$1/",
|
||||
SetupTimeField: "~setuptime2:s/sip:(.+)/$1/",
|
||||
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/")
|
||||
if dc2, err := NewDerivedCharger("test2",
|
||||
"~reqtype2:s/sip:(.+)/$1/",
|
||||
"~direction2:s/sip:(.+)/$1/",
|
||||
"~tenant2:s/sip:(.+)/$1/",
|
||||
"~tor2:s/sip:(.+)/$1/",
|
||||
"~account2:s/sip:(.+)/$1/",
|
||||
"~subject2:s/sip:(.+)/$1/",
|
||||
"~destination2:s/sip:(.+)/$1/",
|
||||
"~setuptime2:s/sip:(.+)/$1/",
|
||||
"~answertime2:s/sip:(.+)/$1/",
|
||||
"~duration2:s/sip:(.+)/$1/"); err != nil {
|
||||
t.Error("Unexpected error", err.Error)
|
||||
} else if !reflect.DeepEqual(edc2, dc2) {
|
||||
t.Errorf("Expecting: %v, received: %v", edc2, dc2)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package config
|
||||
|
||||
import (
|
||||
"code.google.com/p/goconf/conf"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
@@ -27,20 +26,17 @@ import (
|
||||
)
|
||||
|
||||
// Adds support for slice values in config
|
||||
func ConfigSlice(c *conf.ConfigFile, section, valName string) ([]string, error) {
|
||||
sliceStr, errGet := c.GetString(section, valName)
|
||||
if errGet != nil {
|
||||
return nil, errGet
|
||||
}
|
||||
cfgValStrs := strings.Split(sliceStr, ",") // If need arrises, we can make the separator configurable
|
||||
func ConfigSlice(cfgVal string) ([]string, error) {
|
||||
cfgValStrs := strings.Split(cfgVal, ",") // If need arrises, we can make the separator configurable
|
||||
if len(cfgValStrs) == 1 && cfgValStrs[0] == "" { // Prevents returning iterable with empty value
|
||||
return []string{}, nil
|
||||
}
|
||||
for _, elm := range cfgValStrs {
|
||||
for idx, elm := range cfgValStrs {
|
||||
if elm == "" { //One empty element is presented when splitting empty string
|
||||
return nil, errors.New("Empty values in config slice")
|
||||
|
||||
}
|
||||
cfgValStrs[idx] = strings.TrimSpace(elm) // By default spaces are not removed so we do it here to avoid unpredicted results in config
|
||||
}
|
||||
return cfgValStrs, nil
|
||||
}
|
||||
|
||||
@@ -81,17 +81,6 @@ extra_fields = test # Field identifiers of the fields to add in extra fields s
|
||||
enabled = true # Starts Mediator service: <true|false>.
|
||||
rater = test # Address where to reach the Rater: <internal|x.y.z.y:1234>
|
||||
rater_reconnects = 99 # Number of reconnects to rater before giving up.
|
||||
run_ids = test # Identifiers for each mediation run on CDRs
|
||||
subject_fields = test # Name of subject fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
reqtype_fields = test # Name of request type fields to be used during mediation. Use index number in case of .csv cdrs.
|
||||
direction_fields = test # Name of direction fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
tenant_fields = test # Name of tenant fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
tor_fields = test # Name of tor fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
account_fields = test # Name of account fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
destination_fields = test # Name of destination fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
setup_time_fields = test # Name of setup_time fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
answer_time_fields = test # Name of answer_time fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
duration_fields = test # Name of duration fields to be used during mediation. Use index numbers in case of .csv cdrs.
|
||||
|
||||
[session_manager]
|
||||
enabled = true # Starts SessionManager service: <true|false>.
|
||||
@@ -100,23 +89,25 @@ rater = test # Address where to reach the Rater.
|
||||
rater_reconnects = 99 # Number of reconnects to rater before giving up.
|
||||
debit_interval = 99 # Interval to perform debits on.
|
||||
max_call_duration = 99 # Maximum call duration a prepaid call can last
|
||||
run_ids = test # Identifiers of additional sessions control.
|
||||
reqtype_fields = test # Name of request type fields to be used during additional sessions control <""|*default|field_name>.
|
||||
direction_fields = test # Name of direction fields to be used during additional sessions control <""|*default|field_name>.
|
||||
tenant_fields = test # Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
|
||||
tor_fields = test # Name of tor fields to be used during additional sessions control <""|*default|field_name>.
|
||||
account_fields = test # Name of account fields to be used during additional sessions control <""|*default|field_name>.
|
||||
subject_fields = test # Name of fields to be used during additional sessions control <""|*default|field_name>.
|
||||
destination_fields = test # Name of destination fields to be used during additional sessions control <""|*default|field_name>.
|
||||
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>.
|
||||
|
||||
[freeswitch]
|
||||
server = test # Adress where to connect to FreeSWITCH socket.
|
||||
passwd = test # FreeSWITCH socket password.
|
||||
reconnects = 99 # Number of attempts on connect failure.
|
||||
|
||||
[derived_charging]
|
||||
run_ids = test # Identifiers of additional sessions control.
|
||||
reqtype_fields = test # Name of request type fields to be used during additional sessions control <""|*default|field_name>.
|
||||
direction_fields = test # Name of direction fields to be used during additional sessions control <""|*default|field_name>.
|
||||
tenant_fields = test # Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
|
||||
tor_fields = test # Name of tor fields to be used during additional sessions control <""|*default|field_name>.
|
||||
account_fields = test # Name of account fields to be used during additional sessions control <""|*default|field_name>.
|
||||
subject_fields = test # Name of fields to be used during additional sessions control <""|*default|field_name>.
|
||||
destination_fields = test # Name of destination fields to be used during additional sessions control <""|*default|field_name>.
|
||||
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>.
|
||||
|
||||
[history_server]
|
||||
enabled = true # Starts History service: <true|false>.
|
||||
history_dir = test # Location on disk where to store history files.
|
||||
|
||||
@@ -6,34 +6,34 @@
|
||||
|
||||
[global]
|
||||
# ratingdb_type = redis # Rating subsystem database: <redis>.
|
||||
# ratingdb_host = 127.0.0.1 # Rating subsystem database host address.
|
||||
# ratingdb_host = 127.0.0.1 # Rating subsystem database host address.
|
||||
# ratingdb_port = 6379 # Rating subsystem port to reach the database.
|
||||
# ratingdb_name = 10 # Rating subsystem database name to connect to.
|
||||
# ratingdb_user = # Rating subsystem username to use when connecting to database.
|
||||
# ratingdb_passwd = # Rating subsystem password to use when connecting to database.
|
||||
# ratingdb_user = # Rating subsystem username to use when connecting to database.
|
||||
# ratingdb_passwd = # Rating subsystem password to use when connecting to database.
|
||||
# accountdb_type = redis # Accounting subsystem database: <redis>.
|
||||
# accountdb_host = 127.0.0.1 # Accounting subsystem database host address.
|
||||
# accountdb_host = 127.0.0.1 # Accounting subsystem database host address.
|
||||
# accountdb_port = 6379 # Accounting subsystem port to reach the database.
|
||||
# accountdb_name = 11 # Accounting subsystem database name to connect to.
|
||||
# accountdb_user = # Accounting subsystem username to use when connecting to database.
|
||||
# accountdb_user = # Accounting subsystem username to use when connecting to database.
|
||||
# accountdb_passwd = # Accounting subsystem password to use when connecting to database.
|
||||
# stordb_type = mysql # Stor database type to use: <mysql>
|
||||
# stordb_host = 127.0.0.1 # The host to connect to. Values that start with / are for UNIX domain sockets.
|
||||
# stordb_port = 3306 # The port to reach the logdb.
|
||||
# stordb_name = cgrates # The name of the log database to connect to.
|
||||
# stordb_user = cgrates # Username to use when connecting to stordb.
|
||||
# stordb_passwd = CGRateS.org # Password to use when connecting to stordb.
|
||||
# stordb_passwd = CGRateS.org # Password to use when connecting to stordb.
|
||||
# dbdata_encoding = msgpack # The encoding used to store object data in strings: <msgpack|json>
|
||||
# rpc_json_listen = 127.0.0.1:2012 # RPC JSON listening address
|
||||
# rpc_gob_listen = 127.0.0.1:2013 # RPC GOB listening address
|
||||
# http_listen = 127.0.0.1:2080 # HTTP listening address
|
||||
# rpc_json_listen = 127.0.0.1:2012 # RPC JSON listening address
|
||||
# rpc_gob_listen = 127.0.0.1:2013 # RPC GOB listening address
|
||||
# http_listen = 127.0.0.1:2080 # HTTP listening address
|
||||
# default_reqtype = rated # Default request type to consider when missing from requests: <""|prepaid|postpaid|pseudoprepaid|rated>.
|
||||
# default_tor = call # Default Type of Record to consider when missing from requests.
|
||||
# default_tenant = cgrates.org # Default Tenant to consider when missing from requests.
|
||||
# default_tenant = cgrates.org # Default Tenant to consider when missing from requests.
|
||||
# default_subject = cgrates # Default rating Subject to consider when missing from requests.
|
||||
# rounding_method = *middle # Rounding method for floats/costs: <*up|*middle|*down>
|
||||
# rounding_decimals = 4 # Number of decimals to round float/costs at
|
||||
# xmlcfg_path = # Path towards additional config defined in xml file
|
||||
# xmlcfg_path = # Path towards additional config defined in xml file
|
||||
|
||||
[balancer]
|
||||
# enabled = false # Start Balancer service: <true|false>.
|
||||
@@ -51,88 +51,79 @@
|
||||
# mediator = # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
|
||||
[cdre]
|
||||
# cdr_format = csv # Exported CDRs format <csv>
|
||||
# mask_destination_id = # Destination id containing called addresses to be masked on export
|
||||
# mask_length = 0 # Length of the destination suffix to be masked
|
||||
# cost_shift_digits = 0 # Shift cost on export with the number of digits digits defined here (eg: convert from Eur to cent).
|
||||
# cdr_format = csv # Exported CDRs format <csv>
|
||||
# mask_destination_id = # Destination id containing called addresses to be masked on export
|
||||
# mask_length = 0 # Length of the destination suffix to be masked
|
||||
# cost_shift_digits = 0 # Shift cost on export with the number of digits digits defined here (eg: convert from Eur to cent).
|
||||
# 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>
|
||||
# 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>
|
||||
# cdrs_method = http_cgr # Mechanism to use when posting CDRs on server <http_cgr>
|
||||
# run_delay = 0 # Sleep interval in seconds between consecutive runs, 0 to use automation via inotify
|
||||
# cdr_type = csv # CDR file format <csv|freeswitch_csv>.
|
||||
# enabled = false # Enable CDR client functionality
|
||||
# cdrs = internal # Address where to reach CDR server. <internal|127.0.0.1:2080>
|
||||
# cdrs_method = http_cgr # Mechanism to use when posting CDRs on server <http_cgr>
|
||||
# run_delay = 0 # Sleep interval in seconds between consecutive runs, 0 to use automation via inotify
|
||||
# cdr_type = csv # CDR file format <csv|freeswitch_csv>.
|
||||
# cdr_in_dir = /var/log/cgrates/cdrc/in # Absolute path towards the directory where the CDRs are stored.
|
||||
# cdr_out_dir = /var/log/cgrates/cdrc/out # Absolute path towards the directory where processed CDRs will be moved.
|
||||
# cdr_source_id = freeswitch_csv # Free form field, tag identifying the source of the CDRs within CGRS database.
|
||||
# accid_field = 0 # Accounting id field identifier. Use index number in case of .csv cdrs.
|
||||
# reqtype_field = 1 # Request type field identifier. Use index number in case of .csv cdrs.
|
||||
# direction_field = 2 # Direction field identifier. Use index numbers in case of .csv cdrs.
|
||||
# tenant_field = 3 # Tenant field identifier. Use index numbers in case of .csv cdrs.
|
||||
# tor_field = 4 # Type of Record field identifier. Use index numbers in case of .csv cdrs.
|
||||
# account_field = 5 # Account field identifier. Use index numbers in case of .csv cdrs.
|
||||
# subject_field = 6 # Subject field identifier. Use index numbers in case of .csv CDRs.
|
||||
# destination_field = 7 # Destination field identifier. Use index numbers in case of .csv cdrs.
|
||||
# setup_time_field = 8 # Setup time field identifier. Use index numbers in case of .csv cdrs.
|
||||
# answer_time_field = 9 # Answer time field identifier. Use index numbers in case of .csv cdrs.
|
||||
# duration_field = 10 # Duration field identifier. Use index numbers in case of .csv cdrs.
|
||||
# extra_fields = # Extra fields identifiers. For .csv, format: <label_extrafield_1>:<index_extrafield_1>[...,<label_extrafield_n>:<index_extrafield_n>]
|
||||
# cdr_source_id = freeswitch_csv # Free form field, tag identifying the source of the CDRs within CGRS database.
|
||||
# accid_field = 0 # Accounting id field identifier. Use index number in case of .csv cdrs.
|
||||
# reqtype_field = 1 # Request type field identifier. Use index number in case of .csv cdrs.
|
||||
# direction_field = 2 # Direction field identifier. Use index numbers in case of .csv cdrs.
|
||||
# tenant_field = 3 # Tenant field identifier. Use index numbers in case of .csv cdrs.
|
||||
# tor_field = 4 # Type of Record field identifier. Use index numbers in case of .csv cdrs.
|
||||
# account_field = 5 # Account field identifier. Use index numbers in case of .csv cdrs.
|
||||
# subject_field = 6 # Subject field identifier. Use index numbers in case of .csv CDRs.
|
||||
# destination_field = 7 # Destination field identifier. Use index numbers in case of .csv cdrs.
|
||||
# setup_time_field = 8 # Setup time field identifier. Use index numbers in case of .csv cdrs.
|
||||
# answer_time_field = 9 # Answer time field identifier. Use index numbers in case of .csv cdrs.
|
||||
# duration_field = 10 # Duration field identifier. Use index numbers in case of .csv cdrs.
|
||||
# extra_fields = # Extra fields identifiers. For .csv, format: <label_extrafield_1>:<index_extrafield_1>[...,<label_extrafield_n>:<index_extrafield_n>]
|
||||
|
||||
[mediator]
|
||||
# enabled = false # Starts Mediator service: <true|false>.
|
||||
# rater = internal # Address where to reach the Rater: <internal|x.y.z.y:1234>
|
||||
# rater_reconnects = 3 # Number of reconnects to rater before giving up.
|
||||
# run_ids = # Identifiers of each extra mediation to run on CDRs
|
||||
# reqtype_fields = # Name of request type fields to be used during extra mediation. Use index number in case of .csv cdrs.
|
||||
# direction_fields = # Name of direction fields to be used during extra mediation. Use index numbers in case of .csv cdrs.
|
||||
# tenant_fields = # Name of tenant fields to be used during extra mediation. Use index numbers in case of .csv cdrs.
|
||||
# tor_fields = # Name of tor fields to be used during extra mediation. Use index numbers in case of .csv cdrs.
|
||||
# account_fields = # Name of account fields to be used during extra mediation. Use index numbers in case of .csv cdrs.
|
||||
# subject_fields = # Name of fields to be used during extra mediation. Use index numbers in case of .csv cdrs.
|
||||
# destination_fields = # Name of destination fields to be used during extra mediation. Use index numbers in case of .csv cdrs.
|
||||
# setup_time_fields = # Name of setup_time fields to be used during extra mediation. Use index numbers in case of .csv cdrs.
|
||||
# answer_time_fields = # Name of answer_time fields to be used during extra mediation. Use index numbers in case of .csv cdrs.
|
||||
# duration_fields = # Name of duration fields to be used during extra mediation. Use index numbers in case of .csv cdrs.
|
||||
# rater_reconnects = 3 # Number of reconnects to rater before giving up.
|
||||
|
||||
[session_manager]
|
||||
# enabled = false # Starts SessionManager service: <true|false>.
|
||||
# switch_type = freeswitch # Defines the type of switch behind: <freeswitch>.
|
||||
# switch_type = freeswitch # Defines the type of switch behind: <freeswitch>.
|
||||
# rater = internal # Address where to reach the Rater.
|
||||
# rater_reconnects = 3 # Number of reconnects to rater before giving up.
|
||||
# debit_interval = 10 # Interval to perform debits on.
|
||||
# max_call_duration = 3h # Maximum call duration a prepaid call can last
|
||||
# rater_reconnects = 3 # Number of reconnects to rater before giving up.
|
||||
# debit_interval = 10 # Interval to perform debits on.
|
||||
# max_call_duration = 3h # Maximum call duration a prepaid call can last
|
||||
|
||||
[freeswitch]
|
||||
# server = 127.0.0.1:8021 # Adress where to connect to FreeSWITCH socket.
|
||||
# passwd = ClueCon # FreeSWITCH socket password.
|
||||
# reconnects = 5 # Number of attempts on connect failure.
|
||||
|
||||
[derived_charging]
|
||||
# run_ids = # Identifiers of additional sessions control.
|
||||
# reqtype_fields = # Name of request type fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# direction_fields = # Name of direction fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# direction_fields = # Name of direction fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# tenant_fields = # Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# tor_fields = # Name of tor fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# account_fields = # Name of account fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# subject_fields = # Name of fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# destination_fields = # Name of destination fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# 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>.
|
||||
|
||||
[freeswitch]
|
||||
# server = 127.0.0.1:8021 # Adress where to connect to FreeSWITCH socket.
|
||||
# passwd = ClueCon # FreeSWITCH socket password.
|
||||
# reconnects = 5 # Number of attempts on connect failure.
|
||||
# destination_fields = # Name of destination fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# 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>.
|
||||
|
||||
[history_server]
|
||||
# enabled = false # Starts History service: <true|false>.
|
||||
# enabled = false # Starts History service: <true|false>.
|
||||
# history_dir = /var/log/cgrates/history # Location on disk where to store history files.
|
||||
# save_interval = 1s # Interval to save changed cache into .git archive
|
||||
# save_interval = 1s # Interval to save changed cache into .git archive
|
||||
|
||||
[history_agent]
|
||||
# enabled = false # Starts History as a client: <true|false>.
|
||||
# server = internal # Address where to reach the master history server: <internal|x.y.z.y:1234>
|
||||
|
||||
[mailer]
|
||||
# server = localhost # The server to use when sending emails out
|
||||
# auth_user = cgrates # Authenticate to email server using this user
|
||||
# auth_passwd = CGRateS.org # Authenticate to email server with this password
|
||||
# server = localhost # The server to use when sending emails out
|
||||
# auth_user = cgrates # Authenticate to email server using this user
|
||||
# auth_passwd = CGRateS.org # Authenticate to email server with this password
|
||||
# from_address = cgr-mailer@localhost.localdomain # From address used when sending emails out
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
--
|
||||
-- Table structure for table `rater_cdrs`
|
||||
-- Table structure for table `rated_cdrs`
|
||||
--
|
||||
DROP TABLE IF EXISTS `rated_cdrs`;
|
||||
CREATE TABLE `rated_cdrs` (
|
||||
|
||||
@@ -66,7 +66,7 @@ const (
|
||||
COMMENT_CHAR = '#'
|
||||
CSV_SEP = ','
|
||||
FALLBACK_SEP = ';'
|
||||
REGEXP_SEP = "~"
|
||||
REGEXP_PREFIX = "~"
|
||||
JSON = "json"
|
||||
MSGPACK = "msgpack"
|
||||
CSV_LOAD = "CSVLOAD"
|
||||
@@ -99,6 +99,7 @@ const (
|
||||
CDRE = "cdre"
|
||||
MASK_CHAR = "*"
|
||||
CONCATENATED_KEY_SEP = ":"
|
||||
META_DEFAULT = "*default"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -43,7 +43,7 @@ func NewRSRField(fldStr string) (*RSRField, error) {
|
||||
if len(fldStr) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if !strings.HasPrefix(fldStr, REGEXP_SEP) {
|
||||
if !strings.HasPrefix(fldStr, REGEXP_PREFIX) {
|
||||
return &RSRField{Id: fldStr}, nil
|
||||
}
|
||||
if fldId, reSrcRepl, err := ParseSearchReplaceFromFieldRule(fldStr); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user