mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-12 10:36:24 +05:00
merged master
This commit is contained in:
@@ -90,6 +90,7 @@ func (self *Cdrc) parseFieldsConfig() error {
|
||||
utils.ACCOUNT: self.cgrCfg.CdrcAccountField,
|
||||
utils.SUBJECT: self.cgrCfg.CdrcSubjectField,
|
||||
utils.DESTINATION: self.cgrCfg.CdrcDestinationField,
|
||||
utils.SETUP_TIME: self.cgrCfg.CdrcSetupTimeField,
|
||||
utils.ANSWER_TIME: self.cgrCfg.CdrcAnswerTimeField,
|
||||
utils.DURATION: self.cgrCfg.CdrcDurationField,
|
||||
}
|
||||
@@ -153,6 +154,10 @@ func (self *Cdrc) recordAsStoredCdr(record []string) (*utils.StoredCdr, error) {
|
||||
ratedCdr.Subject = fieldVal
|
||||
case utils.DESTINATION:
|
||||
ratedCdr.Destination = fieldVal
|
||||
case utils.SETUP_TIME:
|
||||
if ratedCdr.SetupTime, err = utils.ParseTimeDetectLayout(fieldVal); err != nil {
|
||||
return nil, fmt.Errorf("Cannot parse answer time field, err: %s", err.Error())
|
||||
}
|
||||
case utils.ANSWER_TIME:
|
||||
if ratedCdr.AnswerTime, err = utils.ParseTimeDetectLayout(fieldVal); err != nil {
|
||||
return nil, fmt.Errorf("Cannot parse answer time field, err: %s", err.Error())
|
||||
|
||||
@@ -58,7 +58,7 @@ func TestParseFieldsConfig(t *testing.T) {
|
||||
|
||||
func TestRecordAsStoredCdr(t *testing.T) {
|
||||
cgrConfig, _ := config.NewDefaultCGRConfig()
|
||||
cgrConfig.CdrcExtraFields = []string{"supplier:10"}
|
||||
cgrConfig.CdrcExtraFields = []string{"supplier:11"}
|
||||
cdrc := &Cdrc{cgrCfg: cgrConfig}
|
||||
if err := cdrc.parseFieldsConfig(); err != nil {
|
||||
t.Error("Failed parsing default fieldIndexesFromConfig", err)
|
||||
@@ -68,7 +68,8 @@ func TestRecordAsStoredCdr(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Error("Failed to corectly detect missing fields from record")
|
||||
}
|
||||
cdrRow = []string{"acc1", "prepaid", "*out", "cgrates.org", "call", "1001", "1001", "+4986517174963", "2013-02-03 19:54:00", "62", "supplier1", "172.16.1.1"}
|
||||
cdrRow = []string{"acc1", "prepaid", "*out", "cgrates.org", "call", "1001", "1001", "+4986517174963", "2013-02-03 19:50:00", "2013-02-03 19:54:00", "62",
|
||||
"supplier1", "172.16.1.1"}
|
||||
rtCdr, err := cdrc.recordAsStoredCdr(cdrRow)
|
||||
if err != nil {
|
||||
t.Error("Failed to parse CDR in rated cdr", err)
|
||||
@@ -84,6 +85,7 @@ func TestRecordAsStoredCdr(t *testing.T) {
|
||||
Account: cdrRow[5],
|
||||
Subject: cdrRow[6],
|
||||
Destination: cdrRow[7],
|
||||
SetupTime: time.Date(2013, 2, 3, 19, 50, 0, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 2, 3, 19, 54, 0, 0, time.UTC),
|
||||
Duration: time.Duration(62) * time.Second,
|
||||
ExtraFields: map[string]string{"supplier": "supplier1"},
|
||||
|
||||
@@ -38,7 +38,7 @@ func NewCsvCdrWriter(writer io.Writer, roundDecimals int, extraFields []string)
|
||||
|
||||
func (dcw *CsvCdrWriter) Write(cdr *utils.StoredCdr) error {
|
||||
primaryFields := []string{cdr.CgrId, cdr.MediationRunId, cdr.AccId, cdr.CdrHost, cdr.ReqType, cdr.Direction, cdr.Tenant, cdr.TOR, cdr.Account, cdr.Subject,
|
||||
cdr.Destination, cdr.AnswerTime.String(), strconv.Itoa(int(cdr.Duration)), strconv.FormatFloat(cdr.Cost, 'f', dcw.roundDecimals, 64)}
|
||||
cdr.Destination, cdr.SetupTime.String(), cdr.AnswerTime.String(), strconv.Itoa(int(cdr.Duration)), strconv.FormatFloat(cdr.Cost, 'f', dcw.roundDecimals, 64)}
|
||||
if len(dcw.extraFields) == 0 {
|
||||
dcw.extraFields = utils.MapKeys(cdr.ExtraFields)
|
||||
sort.Strings(dcw.extraFields) // Controlled order in case of dynamic extra fields
|
||||
|
||||
@@ -30,12 +30,13 @@ func TestCsvCdrWriter(t *testing.T) {
|
||||
writer := &bytes.Buffer{}
|
||||
csvCdrWriter := NewCsvCdrWriter(writer, 4, []string{"extra3", "extra1"})
|
||||
ratedCdr := &utils.StoredCdr{CgrId: utils.FSCgrId("dsafdsaf"), AccId: "dsafdsaf", CdrHost: "192.168.1.1", ReqType: "rated", Direction: "*out", Tenant: "cgrates.org",
|
||||
TOR: "call", Account: "1001", Subject: "1001", Destination: "1002", AnswerTime: time.Unix(1383813746, 0).UTC(), Duration: 10, MediationRunId: utils.DEFAULT_RUNID,
|
||||
TOR: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(),
|
||||
Duration: 10, MediationRunId: utils.DEFAULT_RUNID,
|
||||
ExtraFields: map[string]string{"extra1": "val_extra1", "extra2": "val_extra2", "extra3": "val_extra3"}, Cost: 1.01,
|
||||
}
|
||||
csvCdrWriter.Write(ratedCdr)
|
||||
csvCdrWriter.Close()
|
||||
expected := "b18944ef4dc618569f24c27b9872827a242bad0c,default,dsafdsaf,192.168.1.1,rated,*out,cgrates.org,call,1001,1001,1002,2013-11-07 08:42:26 +0000 UTC,10,1.0100,val_extra3,val_extra1"
|
||||
expected := "b18944ef4dc618569f24c27b9872827a242bad0c,default,dsafdsaf,192.168.1.1,rated,*out,cgrates.org,call,1001,1001,1002,2013-11-07 08:42:25 +0000 UTC,2013-11-07 08:42:26 +0000 UTC,10,1.0100,val_extra3,val_extra1"
|
||||
result := strings.TrimSpace(writer.String())
|
||||
if result != expected {
|
||||
t.Errorf("Expected %s received %s.", expected, result)
|
||||
|
||||
@@ -41,6 +41,7 @@ const (
|
||||
FS_CSTMID = "cgr_tenant"
|
||||
FS_CALL_DEST_NR = "dialed_extension"
|
||||
FS_PARK_TIME = "start_epoch"
|
||||
FS_SETUP_TIME = "start_epoch"
|
||||
FS_ANSWER_TIME = "answer_epoch"
|
||||
FS_HANGUP_TIME = "end_epoch"
|
||||
FS_DURATION = "billsec"
|
||||
@@ -114,6 +115,12 @@ func (fsCdr FSCdr) GetExtraFields() map[string]string {
|
||||
}
|
||||
return extraFields
|
||||
}
|
||||
func (fsCdr FSCdr) GetSetupTime() (t time.Time, err error) {
|
||||
//ToDo: Make sure we work with UTC instead of local time
|
||||
at, err := strconv.ParseInt(fsCdr[FS_SETUP_TIME], 0, 64)
|
||||
t = time.Unix(at, 0)
|
||||
return
|
||||
}
|
||||
func (fsCdr FSCdr) GetAnswerTime() (t time.Time, err error) {
|
||||
//ToDo: Make sure we work with UTC instead of local time
|
||||
at, err := strconv.ParseInt(fsCdr[FS_ANSWER_TIME], 0, 64)
|
||||
@@ -163,13 +170,13 @@ func (fsCdr FSCdr) Restore(input string) error {
|
||||
}
|
||||
|
||||
// Used in extra mediation
|
||||
func (fsCdr FSCdr) AsStoredCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, answerTimeFld, durationFld string, extraFlds []string, fieldsMandatory bool) (*utils.StoredCdr, error) {
|
||||
func (fsCdr FSCdr) AsStoredCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, setupTimeFld, answerTimeFld, durationFld string, extraFlds []string, fieldsMandatory bool) (*utils.StoredCdr, error) {
|
||||
if utils.IsSliceMember([]string{runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, answerTimeFld, durationFld}, "") {
|
||||
return nil, errors.New(fmt.Sprintf("%s:FieldName", utils.ERR_MANDATORY_IE_MISSING)) // All input field names are mandatory
|
||||
}
|
||||
var err error
|
||||
var hasKey bool
|
||||
var aTimeStr, durStr string
|
||||
var sTimeStr, aTimeStr, durStr string
|
||||
rtCdr := new(utils.StoredCdr)
|
||||
rtCdr.MediationRunId = runId
|
||||
rtCdr.Cost = -1.0 // Default for non-rated CDR
|
||||
@@ -223,6 +230,16 @@ func (fsCdr FSCdr) AsStoredCdr(runId, reqTypeFld, directionFld, tenantFld, torFl
|
||||
} else if rtCdr.Destination, hasKey = fsCdr[destFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", utils.ERR_MANDATORY_IE_MISSING, destFld))
|
||||
}
|
||||
if sTimeStr, hasKey = fsCdr[setupTimeFld]; !hasKey && fieldsMandatory && !strings.HasPrefix(setupTimeFld, utils.STATIC_VALUE_PREFIX) {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", utils.ERR_MANDATORY_IE_MISSING, setupTimeFld))
|
||||
} else {
|
||||
if strings.HasPrefix(setupTimeFld, utils.STATIC_VALUE_PREFIX) {
|
||||
sTimeStr = setupTimeFld[1:]
|
||||
}
|
||||
if rtCdr.SetupTime, err = utils.ParseTimeDetectLayout(sTimeStr); err != nil && fieldsMandatory {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if aTimeStr, hasKey = fsCdr[answerTimeFld]; !hasKey && fieldsMandatory && !strings.HasPrefix(answerTimeFld, utils.STATIC_VALUE_PREFIX) {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", utils.ERR_MANDATORY_IE_MISSING, answerTimeFld))
|
||||
} else {
|
||||
|
||||
@@ -75,6 +75,11 @@ func TestCDRFields(t *testing.T) {
|
||||
if fsCdr.GetReqType() != utils.RATED {
|
||||
t.Error("Error parsing cdr: ", fsCdr)
|
||||
}
|
||||
setupTime, _ := fsCdr.GetSetupTime()
|
||||
expectedSTime, _ := time.Parse(time.RFC3339, "2013-08-04T09:50:54Z")
|
||||
if setupTime.UTC() != expectedSTime {
|
||||
t.Error("Error parsing cdr: ", fsCdr)
|
||||
}
|
||||
answerTime, _ := fsCdr.GetAnswerTime()
|
||||
expectedATime, _ := time.Parse(time.RFC3339, "2013-08-04T09:50:56Z")
|
||||
if answerTime.UTC() != expectedATime {
|
||||
@@ -100,7 +105,7 @@ func TestFsCdrAsStoredCdr(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Error loading cdr: %v", err)
|
||||
}
|
||||
rtCdrOut, err := fsCdr.AsStoredCdr("wholesale_run", "^"+utils.RATED, "^*out", "cgr_tenant", "cgr_tor", "cgr_account", "cgr_subject", "cgr_destination",
|
||||
rtCdrOut, err := fsCdr.AsStoredCdr("wholesale_run", "^"+utils.RATED, "^*out", "cgr_tenant", "cgr_tor", "cgr_account", "cgr_subject", "cgr_destination", "start_epoch",
|
||||
"answer_epoch", "billsec", []string{"effective_caller_id_number"}, true)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error received", err)
|
||||
@@ -108,25 +113,27 @@ func TestFsCdrAsStoredCdr(t *testing.T) {
|
||||
expctRatedCdr := &utils.StoredCdr{CgrId: utils.FSCgrId("01df56f4-d99a-4ef6-b7fe-b924b2415b7f"), AccId: "01df56f4-d99a-4ef6-b7fe-b924b2415b7f",
|
||||
CdrHost: "127.0.0.1", CdrSource: FS_CDR_SOURCE, ReqType: utils.RATED,
|
||||
Direction: "*out", Tenant: "ipbx.itsyscom.com", TOR: "call", Account: "dan", Subject: "dan", Destination: "+4986517174963",
|
||||
SetupTime: time.Date(2013, 8, 4, 9, 50, 54, 0, time.UTC).Local(),
|
||||
AnswerTime: time.Date(2013, 8, 4, 9, 50, 56, 0, time.UTC).Local(), Duration: time.Duration(4) * time.Second,
|
||||
ExtraFields: map[string]string{"effective_caller_id_number": "+4986517174960"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
if !reflect.DeepEqual(rtCdrOut, expctRatedCdr) {
|
||||
t.Errorf("Received: %v, expected: %v", rtCdrOut, expctRatedCdr)
|
||||
}
|
||||
rtCdrOut2, err := fsCdr.AsStoredCdr("wholesale_run", "^postpaid", "^*in", "^cgrates.com", "^premium_call", "^first_account", "^first_subject", "cgr_destination",
|
||||
"^2013-12-07T08:42:26Z", "^12s", []string{"effective_caller_id_number"}, true)
|
||||
"^2013-12-07T08:42:24Z", "^2013-12-07T08:42:26Z", "^12s", []string{"effective_caller_id_number"}, true)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error received", err)
|
||||
}
|
||||
expctRatedCdr2 := &utils.StoredCdr{CgrId: utils.FSCgrId("01df56f4-d99a-4ef6-b7fe-b924b2415b7f"), AccId: "01df56f4-d99a-4ef6-b7fe-b924b2415b7f", CdrHost: "127.0.0.1",
|
||||
CdrSource: FS_CDR_SOURCE, ReqType: "postpaid",
|
||||
Direction: "*in", Tenant: "cgrates.com", TOR: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "+4986517174963",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Duration: time.Duration(12) * time.Second,
|
||||
ExtraFields: map[string]string{"effective_caller_id_number": "+4986517174960"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
if !reflect.DeepEqual(rtCdrOut2, expctRatedCdr2) {
|
||||
t.Errorf("Received: %v, expected: %v", rtCdrOut2, expctRatedCdr2)
|
||||
}
|
||||
_, err = fsCdr.AsStoredCdr("wholesale_run", "dummy_header", "direction", "tenant", "tor", "account", "subject", "destination", "answer_time", "duration", []string{"field_extr1", "fieldextr2"}, true)
|
||||
_, err = fsCdr.AsStoredCdr("wholesale_run", "dummy_header", "direction", "tenant", "tor", "account", "subject", "destination", "setup_time", "answer_time", "duration", []string{"field_extr1", "fieldextr2"}, true)
|
||||
if err == nil {
|
||||
t.Error("Failed to detect missing header")
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ type CGRConfig struct {
|
||||
CdrcAccountField string // Account field identifier. Use index numbers in case of .csv cdrs.
|
||||
CdrcSubjectField string // Subject field identifier. Use index numbers in case of .csv CDRs.
|
||||
CdrcDestinationField string // Destination field identifier. Use index numbers in case of .csv cdrs.
|
||||
CdrcSetupTimeField string // Setup time field identifier. Use index numbers in case of .csv cdrs.
|
||||
CdrcAnswerTimeField string // Answer time field identifier. Use index numbers in case of .csv cdrs.
|
||||
CdrcDurationField string // Duration field identifier. Use index numbers in case of .csv cdrs.
|
||||
CdrcExtraFields []string // Field identifiers of the fields to add in extra fields section, special format in case of .csv "field1:index1,field2:index2"
|
||||
@@ -115,6 +116,7 @@ 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>.
|
||||
@@ -122,7 +124,8 @@ type CGRConfig struct {
|
||||
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>.
|
||||
SMAnswerTimeFields []string // Name of time_answer 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>
|
||||
@@ -135,7 +138,8 @@ type CGRConfig struct {
|
||||
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.
|
||||
MediatorAnswerTimeFields []string // Name of time_start 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.
|
||||
FreeswitchServer string // freeswitch address host:port
|
||||
FreeswitchPass string // FS socket password
|
||||
@@ -206,8 +210,9 @@ func (self *CGRConfig) setDefaults() error {
|
||||
self.CdrcAccountField = "5"
|
||||
self.CdrcSubjectField = "6"
|
||||
self.CdrcDestinationField = "7"
|
||||
self.CdrcAnswerTimeField = "8"
|
||||
self.CdrcDurationField = "9"
|
||||
self.CdrcSetupTimeField = "8"
|
||||
self.CdrcAnswerTimeField = "9"
|
||||
self.CdrcDurationField = "10"
|
||||
self.CdrcExtraFields = []string{}
|
||||
self.MediatorEnabled = false
|
||||
self.MediatorRater = "internal"
|
||||
@@ -220,6 +225,7 @@ func (self *CGRConfig) setDefaults() error {
|
||||
self.MediatorTORFields = []string{}
|
||||
self.MediatorAccountFields = []string{}
|
||||
self.MediatorDestFields = []string{}
|
||||
self.MediatorSetupTimeFields = []string{}
|
||||
self.MediatorAnswerTimeFields = []string{}
|
||||
self.MediatorDurationFields = []string{}
|
||||
self.SMEnabled = false
|
||||
@@ -228,6 +234,7 @@ 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{}
|
||||
@@ -235,6 +242,7 @@ func (self *CGRConfig) setDefaults() error {
|
||||
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"
|
||||
@@ -449,6 +457,9 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
if hasOpt = c.HasOption("cdrc", "destination_field"); hasOpt {
|
||||
cfg.CdrcDestinationField, _ = c.GetString("cdrc", "destination_field")
|
||||
}
|
||||
if hasOpt = c.HasOption("cdrc", "setup_time_field"); hasOpt {
|
||||
cfg.CdrcSetupTimeField, _ = c.GetString("cdrc", "setup_time_field")
|
||||
}
|
||||
if hasOpt = c.HasOption("cdrc", "answer_time_field"); hasOpt {
|
||||
cfg.CdrcAnswerTimeField, _ = c.GetString("cdrc", "answer_time_field")
|
||||
}
|
||||
@@ -509,6 +520,11 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
return nil, errParse
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "setup_time_fields"); hasOpt {
|
||||
if cfg.MediatorSetupTimeFields, errParse = ConfigSlice(c, "mediator", "setup_time_fields"); errParse != nil {
|
||||
return nil, errParse
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("mediator", "answer_time_fields"); hasOpt {
|
||||
if cfg.MediatorAnswerTimeFields, errParse = ConfigSlice(c, "mediator", "answer_time_fields"); errParse != nil {
|
||||
return nil, errParse
|
||||
@@ -540,7 +556,11 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
return nil, errParse
|
||||
}
|
||||
}
|
||||
|
||||
if hasOpt = c.HasOption("session_manager", "run_ids"); hasOpt {
|
||||
if cfg.SMRunIds, errParse = ConfigSlice(c, "session_manager", "run_ids"); errParse != nil {
|
||||
return nil, errParse
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "reqtype_fields"); hasOpt {
|
||||
if cfg.SMReqTypeFields, errParse = ConfigSlice(c, "session_manager", "reqtype_fields"); errParse != nil {
|
||||
return nil, errParse
|
||||
@@ -576,6 +596,11 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) {
|
||||
return nil, errParse
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "setup_time_fields"); hasOpt {
|
||||
if cfg.SMSetupTimeFields, errParse = ConfigSlice(c, "session_manager", "setup_time_fields"); errParse != nil {
|
||||
return nil, errParse
|
||||
}
|
||||
}
|
||||
if hasOpt = c.HasOption("session_manager", "answer_time_fields"); hasOpt {
|
||||
if cfg.SMAnswerTimeFields, errParse = ConfigSlice(c, "session_manager", "answer_time_fields"); errParse != nil {
|
||||
return nil, errParse
|
||||
|
||||
@@ -99,8 +99,9 @@ func TestDefaults(t *testing.T) {
|
||||
eCfg.CdrcAccountField = "5"
|
||||
eCfg.CdrcSubjectField = "6"
|
||||
eCfg.CdrcDestinationField = "7"
|
||||
eCfg.CdrcAnswerTimeField = "8"
|
||||
eCfg.CdrcDurationField = "9"
|
||||
eCfg.CdrcSetupTimeField = "8"
|
||||
eCfg.CdrcAnswerTimeField = "9"
|
||||
eCfg.CdrcDurationField = "10"
|
||||
eCfg.CdrcExtraFields = []string{}
|
||||
eCfg.MediatorEnabled = false
|
||||
eCfg.MediatorRater = "internal"
|
||||
@@ -113,6 +114,7 @@ func TestDefaults(t *testing.T) {
|
||||
eCfg.MediatorTORFields = []string{}
|
||||
eCfg.MediatorAccountFields = []string{}
|
||||
eCfg.MediatorDestFields = []string{}
|
||||
eCfg.MediatorSetupTimeFields = []string{}
|
||||
eCfg.MediatorAnswerTimeFields = []string{}
|
||||
eCfg.MediatorDurationFields = []string{}
|
||||
eCfg.SMEnabled = false
|
||||
@@ -121,13 +123,15 @@ func TestDefaults(t *testing.T) {
|
||||
eCfg.SMRaterReconnects = 3
|
||||
eCfg.SMDebitInterval = 10
|
||||
eCfg.SMMaxCallDuration = time.Duration(3) * time.Hour
|
||||
eCfg.SMRunIds = []string{}
|
||||
eCfg.SMReqTypeFields = []string{}
|
||||
eCfg.SMDirectionFields = []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"
|
||||
@@ -232,6 +236,7 @@ func TestConfigFromFile(t *testing.T) {
|
||||
eCfg.CdrcAccountField = "test"
|
||||
eCfg.CdrcSubjectField = "test"
|
||||
eCfg.CdrcDestinationField = "test"
|
||||
eCfg.CdrcSetupTimeField = "test"
|
||||
eCfg.CdrcAnswerTimeField = "test"
|
||||
eCfg.CdrcDurationField = "test"
|
||||
eCfg.CdrcExtraFields = []string{"test"}
|
||||
@@ -246,6 +251,7 @@ func TestConfigFromFile(t *testing.T) {
|
||||
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
|
||||
@@ -254,13 +260,15 @@ func TestConfigFromFile(t *testing.T) {
|
||||
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.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"
|
||||
|
||||
@@ -2,34 +2,34 @@
|
||||
#
|
||||
|
||||
[global]
|
||||
ratingdb_type = test # Rating subsystem database: <redis>.
|
||||
ratingdb_host = test # Rating subsystem database host address.
|
||||
ratingdb_port = test # Rating subsystem port to reach the database.
|
||||
ratingdb_name = test # Rating subsystem database name to connect to.
|
||||
ratingdb_user = test # Rating subsystem username to use when connecting to database.
|
||||
ratingdb_passwd = test # Rating subsystem password to use when connecting to database.
|
||||
accountdb_type = test # Accounting subsystem database: <redis>.
|
||||
accountdb_host = test # Accounting subsystem database host address.
|
||||
accountdb_port = test # Accounting subsystem port to reach the database.
|
||||
accountdb_name = test # Accounting subsystem database name to connect to.
|
||||
accountdb_user = test # Accounting subsystem username to use when connecting to database.
|
||||
accountdb_passwd = test # Accounting subsystem password to use when connecting to database.
|
||||
stordb_type = test # Log/stored database type to use: <same|postgres|mongo|redis>
|
||||
stordb_host = test # The host to connect to. Values that start with / are for UNIX domain sockets.
|
||||
stordb_port = test # The port to reach the logdb.
|
||||
stordb_name = test # The name of the log database to connect to.
|
||||
stordb_user = test # Username to use when connecting to logdb.
|
||||
stordb_passwd = test # Password to use when connecting to logdb.
|
||||
dbdata_encoding = test # The encoding used to store object data in strings: <msgpack|json>
|
||||
rpc_json_listen = test # RPC JSON listening address
|
||||
rpc_gob_listen = test # RPC GOB listening address
|
||||
http_listen = test # HTTP listening address
|
||||
default_reqtype = test # Default request type to consider when missing from requests: <""|prepaid|postpaid|pseudoprepaid|rated>.
|
||||
default_tor = test # Default Type of Record to consider when missing from requests.
|
||||
default_tenant = test # Default Tenant to consider when missing from requests.
|
||||
default_subject = test # Default rating Subject to consider when missing from requests.
|
||||
rounding_method = test # Rounding method for floats/costs: <up|middle|down>
|
||||
rounding_decimals = 99 # Number of decimals to round floats/costs at
|
||||
ratingdb_type = test # Rating subsystem database: <redis>.
|
||||
ratingdb_host = test # Rating subsystem database host address.
|
||||
ratingdb_port = test # Rating subsystem port to reach the database.
|
||||
ratingdb_name = test # Rating subsystem database name to connect to.
|
||||
ratingdb_user = test # Rating subsystem username to use when connecting to database.
|
||||
ratingdb_passwd = test # Rating subsystem password to use when connecting to database.
|
||||
accountdb_type = test # Accounting subsystem database: <redis>.
|
||||
accountdb_host = test # Accounting subsystem database host address.
|
||||
accountdb_port = test # Accounting subsystem port to reach the database.
|
||||
accountdb_name = test # Accounting subsystem database name to connect to.
|
||||
accountdb_user = test # Accounting subsystem username to use when connecting to database.
|
||||
accountdb_passwd = test # Accounting subsystem password to use when connecting to database.
|
||||
stordb_type = test # Log/stored database type to use: <same|postgres|mongo|redis>
|
||||
stordb_host = test # The host to connect to. Values that start with / are for UNIX domain sockets.
|
||||
stordb_port = test # The port to reach the logdb.
|
||||
stordb_name = test # The name of the log database to connect to.
|
||||
stordb_user = test # Username to use when connecting to logdb.
|
||||
stordb_passwd = test # Password to use when connecting to logdb.
|
||||
dbdata_encoding = test # The encoding used to store object data in strings: <msgpack|json>
|
||||
rpc_json_listen = test # RPC JSON listening address
|
||||
rpc_gob_listen = test # RPC GOB listening address
|
||||
http_listen = test # HTTP listening address
|
||||
default_reqtype = test # Default request type to consider when missing from requests: <""|prepaid|postpaid|pseudoprepaid|rated>.
|
||||
default_tor = test # Default Type of Record to consider when missing from requests.
|
||||
default_tenant = test # Default Tenant to consider when missing from requests.
|
||||
default_subject = test # Default rating Subject to consider when missing from requests.
|
||||
rounding_method = test # Rounding method for floats/costs: <up|middle|down>
|
||||
rounding_decimals = 99 # Number of decimals to round floats/costs at
|
||||
|
||||
|
||||
[balancer]
|
||||
@@ -37,7 +37,7 @@ enabled = true # Start Balancer service: <true|false>.
|
||||
|
||||
[rater]
|
||||
enabled = true # Enable Rater service: <true|false>.
|
||||
balancer = test # Register to Balancer as worker: <enabled|disabled>.
|
||||
balancer = test # Register to Balancer as worker: <enabled|disabled>.
|
||||
|
||||
[scheduler]
|
||||
enabled = true # Starts Scheduler service: <true|false>.
|
||||
@@ -48,9 +48,9 @@ extra_fields = test # Extra fields to store in CDRs
|
||||
mediator = test # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
|
||||
[cdre]
|
||||
cdr_format = test # Exported CDRs format <csv>
|
||||
extra_fields = test # List of extra fields to be exported out in CDRs
|
||||
export_dir = test # Path where the exported CDRs will be placed
|
||||
cdr_format = test # Exported CDRs format <csv>
|
||||
extra_fields = test # List of extra fields to be exported out in CDRs
|
||||
export_dir = test # Path where the exported CDRs will be placed
|
||||
|
||||
[cdrc]
|
||||
enabled = true # Enable CDR client functionality
|
||||
@@ -69,23 +69,25 @@ tor_field = test # Type of Record field identifier. Use index numbers in case
|
||||
account_field = test # Account field identifier. Use index numbers in case of .csv cdrs.
|
||||
subject_field = test # Subject field identifier. Use index numbers in case of .csv CDRs.
|
||||
destination_field = test # Destination field identifier. Use index numbers in case of .csv cdrs.
|
||||
setup_time_field = test # Answer time field identifier. Use index numbers in case of .csv cdrs.
|
||||
answer_time_field = test # Answer time field identifier. Use index numbers in case of .csv cdrs.
|
||||
duration_field = test # Duration field identifier. Use index numbers in case of .csv cdrs.
|
||||
extra_fields = test # Field identifiers of the fields to add in extra fields section, special format in case of .csv "index1:field1,index2:field2"
|
||||
|
||||
[mediator]
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
answer_time_fields = test # Name of time_answer 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]
|
||||
@@ -95,6 +97,7 @@ 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>.
|
||||
@@ -102,25 +105,26 @@ tor_fields = test # Name of tor fields to be used during additional sessions c
|
||||
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>.
|
||||
answer_time_fields = test # Name of time_answer 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.
|
||||
server = test # Adress where to connect to FreeSWITCH socket.
|
||||
passwd = test # FreeSWITCH socket password.
|
||||
reconnects = 99 # Number of attempts on connect failure.
|
||||
|
||||
[history_server]
|
||||
enabled = true # Starts History service: <true|false>.
|
||||
history_dir = test # Location on disk where to store history files.
|
||||
save_interval = 99 # Timeout duration between saves
|
||||
enabled = true # Starts History service: <true|false>.
|
||||
history_dir = test # Location on disk where to store history files.
|
||||
save_interval = 99 # Timeout duration between saves
|
||||
|
||||
[history_agent]
|
||||
enabled = true # Starts History as a client: <true|false>.
|
||||
server = test # Address where to reach the master history server: <internal|x.y.z.y:1234>
|
||||
enabled = true # Starts History as a client: <true|false>.
|
||||
server = test # Address where to reach the master history server: <internal|x.y.z.y:1234>
|
||||
|
||||
[mailer]
|
||||
server = test # The server to use when sending emails out
|
||||
auth_user = test # Authenticate to email server using this user
|
||||
auth_passwd = test # Authenticate to email server with this password
|
||||
from_address = test # From address used when sending emails out
|
||||
server = test # The server to use when sending emails out
|
||||
auth_user = test # Authenticate to email server using this user
|
||||
auth_passwd = test # Authenticate to email server with this password
|
||||
from_address = test # From address used when sending emails out
|
||||
|
||||
@@ -71,8 +71,9 @@
|
||||
# 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.
|
||||
# answer_time_field = 8 # Answer time field identifier. Use index numbers in case of .csv cdrs.
|
||||
# duration_field = 9 # Duration 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]
|
||||
@@ -87,7 +88,8 @@
|
||||
# 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.
|
||||
# answer_time_fields = # Name of time_answer 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.
|
||||
|
||||
[session_manager]
|
||||
@@ -97,6 +99,7 @@
|
||||
# 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
|
||||
# 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>.
|
||||
# tenant_fields = # Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
|
||||
@@ -104,7 +107,8 @@
|
||||
# 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>.
|
||||
# answer_time_fields = # Name of time_answer 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>.
|
||||
|
||||
|
||||
|
||||
@@ -4,127 +4,32 @@
|
||||
# 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>.
|
||||
# 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.
|
||||
# accountdb_type = redis # Accounting subsystem database: <redis>.
|
||||
# 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_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.
|
||||
# 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
|
||||
# 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_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
|
||||
|
||||
[balancer]
|
||||
# enabled = false # Start Balancer service: <true|false>.
|
||||
|
||||
[rater]
|
||||
enabled = true # Enable RaterCDRSExportPath service: <true|false>.
|
||||
# balancer = # Register to Balancer as worker: <""|internal|127.0.0.1:2013>.
|
||||
|
||||
[scheduler]
|
||||
enabled = true # Starts Scheduler service: <true|false>.
|
||||
|
||||
[cdrs]
|
||||
enabled = true # Start the CDR Server service: <true|false>.
|
||||
# extra_fields = # Extra fields to store in CDRs for non-generic CDRs
|
||||
mediator = internal # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
|
||||
[cdre]
|
||||
# cdr_format = csv # Exported CDRs format <csv>
|
||||
# extra_fields = # List of extra fields to be exported out in CDRs
|
||||
export_dir = /tmp/cgrates/cdr/cdrexport/csv # Path where the exported CDRs will be placed
|
||||
|
||||
[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>.
|
||||
cdr_in_dir = /tmp/cgrates/cdr/cdrc/in # Absolute path towards the directory where the CDRs are stored.
|
||||
cdr_out_dir =/tmp/cgrates/cdr/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.
|
||||
# answer_time_field = 8 # Answer time field identifier. Use index numbers in case of .csv cdrs.
|
||||
# duration_field = 9 # 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 = true # Starts Mediator service: <true|false>.
|
||||
rater = 127.0.0.1:2012 # 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.
|
||||
# answer_time_fields = # Name of time_answer 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.
|
||||
|
||||
[session_manager]
|
||||
# enabled = false # Starts SessionManager service: <true|false>.
|
||||
# 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
|
||||
# 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>.
|
||||
# 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>.
|
||||
# answer_time_fields = # Name of time_answer 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.
|
||||
|
||||
[history_server]
|
||||
enabled = true # Starts History service: <true|false>.
|
||||
history_dir = /tmp/cgrates/history # Location on disk where to store history files.
|
||||
# save_interval = 1s # Interval to save changed cache into .git archive
|
||||
|
||||
[history_agent]
|
||||
enabled = true # 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
|
||||
# from_address = cgr-mailer@localhost.localdomain # From address used when sending emails out
|
||||
|
||||
|
||||
@@ -3,117 +3,18 @@
|
||||
# Used in mediator_local_test
|
||||
# Starts rater, cdrs and mediator connecting over internal channel
|
||||
|
||||
[global]
|
||||
# ratingdb_type = redis # Rating subsystem database: <redis>.
|
||||
# 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.
|
||||
# accountdb_type = redis # Accounting subsystem database: <redis>.
|
||||
# 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_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.
|
||||
# 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
|
||||
# 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_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
|
||||
|
||||
[balancer]
|
||||
# enabled = false # Start Balancer service: <true|false>.
|
||||
|
||||
[rater]
|
||||
enabled = true # Enable RaterCDRSExportPath service: <true|false>.
|
||||
# balancer = # Register to Balancer as worker: <""|internal|127.0.0.1:2013>.
|
||||
|
||||
[scheduler]
|
||||
# enabled = false # Starts Scheduler service: <true|false>.
|
||||
|
||||
[cdrs]
|
||||
enabled = true # Start the CDR Server service: <true|false>.
|
||||
# extra_fields = # Extra fields to store in CDRs in case of non generic CDRs
|
||||
mediator = internal # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
|
||||
[cdre]
|
||||
# cdr_format = csv # Exported CDRs format <csv>
|
||||
# extra_fields = # List of extra fields to be exported out in CDRs
|
||||
export_dir = /tmp/cgrates/cdr/cdrexport/csv # Path where the exported CDRs will be placed
|
||||
|
||||
[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>.
|
||||
# cdr_in_dir = /var/log/cgrates/cdr/cdrc/in # Absolute path towards the directory where the CDRs are stored.
|
||||
# cdr_out_dir = /var/log/cgrates/cdr/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.
|
||||
# answer_time_field = 8 # Answer time field identifier. Use index numbers in case of .csv cdrs.
|
||||
# duration_field = 9 # 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 = true # 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.
|
||||
# answer_time_fields = # Name of time_answer 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.
|
||||
|
||||
[session_manager]
|
||||
# enabled = false # Starts SessionManager service: <true|false>.
|
||||
# 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
|
||||
|
||||
[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.
|
||||
|
||||
[history_server]
|
||||
# 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
|
||||
|
||||
[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
|
||||
# from_address = cgr-mailer@localhost.localdomain # From address used when sending emails out
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ CREATE TABLE cdrs_primary (
|
||||
account varchar(128) NOT NULL,
|
||||
subject varchar(128) NOT NULL,
|
||||
destination varchar(128) NOT NULL,
|
||||
setup_time datetime NOT NULL,
|
||||
answer_time datetime NOT NULL,
|
||||
duration bigint NOT NULL,
|
||||
PRIMARY KEY (tbid),
|
||||
|
||||
@@ -514,8 +514,9 @@ func (self *SQLStorage) LogError(uuid, source, runid, errstr string) (err error)
|
||||
|
||||
func (self *SQLStorage) SetCdr(cdr utils.RawCDR) (err error) {
|
||||
// map[account:1001 direction:out orig_ip:172.16.1.1 tor:call accid:accid23 answer_time:2013-02-03 19:54:00 cdrsource:freeswitch_csv destination:+4986517174963 duration:62 reqtype:prepaid subject:1001 supplier:supplier1 tenant:cgrates.org]
|
||||
startTime, _ := cdr.GetAnswerTime() // Ignore errors, we want to store the cdr no matter what
|
||||
_, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s VALUES (NULL,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s', %d)",
|
||||
setupTime, _ := cdr.GetSetupTime() // Ignore errors, we want to store the cdr no matter what
|
||||
answerTime, _ := cdr.GetAnswerTime() // Ignore errors, we want to store the cdr no matter what
|
||||
_, err = self.Db.Exec(fmt.Sprintf("INSERT INTO %s VALUES (NULL,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s', %d)",
|
||||
utils.TBL_CDRS_PRIMARY,
|
||||
cdr.GetCgrId(),
|
||||
cdr.GetAccId(),
|
||||
@@ -528,7 +529,8 @@ func (self *SQLStorage) SetCdr(cdr utils.RawCDR) (err error) {
|
||||
cdr.GetAccount(),
|
||||
cdr.GetSubject(),
|
||||
cdr.GetDestination(),
|
||||
startTime,
|
||||
setupTime,
|
||||
answerTime,
|
||||
cdr.GetDuration(),
|
||||
))
|
||||
if err != nil {
|
||||
@@ -569,7 +571,7 @@ func (self *SQLStorage) SetRatedCdr(storedCdr *utils.StoredCdr, extraInfo string
|
||||
// ignoreRated - do not consider cdrs which were already rated, including here the ones with errors
|
||||
func (self *SQLStorage) GetStoredCdrs(timeStart, timeEnd time.Time, ignoreErr, ignoreRated bool) ([]*utils.StoredCdr, error) {
|
||||
var cdrs []*utils.StoredCdr
|
||||
q := fmt.Sprintf("SELECT %s.cgrid,accid,cdrhost,cdrsource,reqtype,direction,tenant,tor,account,%s.subject,destination,answer_time,duration,extra_fields,runid,cost FROM %s LEFT JOIN %s ON %s.cgrid=%s.cgrid LEFT JOIN %s ON %s.cgrid=%s.cgrid", utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA, utils.TBL_RATED_CDRS, utils.TBL_CDRS_PRIMARY, utils.TBL_RATED_CDRS)
|
||||
q := fmt.Sprintf("SELECT %s.cgrid,accid,cdrhost,cdrsource,reqtype,direction,tenant,tor,account,%s.subject,destination,setup_time,answer_time,duration,extra_fields,runid,cost FROM %s LEFT JOIN %s ON %s.cgrid=%s.cgrid LEFT JOIN %s ON %s.cgrid=%s.cgrid", utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA, utils.TBL_CDRS_PRIMARY, utils.TBL_CDRS_EXTRA, utils.TBL_RATED_CDRS, utils.TBL_CDRS_PRIMARY, utils.TBL_RATED_CDRS)
|
||||
fltr := ""
|
||||
if !timeStart.IsZero() {
|
||||
if len(fltr) != 0 {
|
||||
@@ -609,12 +611,12 @@ func (self *SQLStorage) GetStoredCdrs(timeStart, timeEnd time.Time, ignoreErr, i
|
||||
for rows.Next() {
|
||||
var cgrid, accid, cdrhost, cdrsrc, reqtype, direction, tenant, tor, account, subject, destination string
|
||||
var extraFields []byte
|
||||
var answerTime time.Time
|
||||
var setupTime, answerTime time.Time
|
||||
var duration int64
|
||||
var runid sql.NullString // So we can export unmediated CDRs
|
||||
var cost sql.NullFloat64 // So we can export unmediated CDRs
|
||||
var extraFieldsMp map[string]string
|
||||
if err := rows.Scan(&cgrid, &accid, &cdrhost, &cdrsrc, &reqtype, &direction, &tenant, &tor, &account, &subject, &destination, &answerTime, &duration,
|
||||
if err := rows.Scan(&cgrid, &accid, &cdrhost, &cdrsrc, &reqtype, &direction, &tenant, &tor, &account, &subject, &destination, &setupTime, &answerTime, &duration,
|
||||
&extraFields, &runid, &cost); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -623,7 +625,7 @@ func (self *SQLStorage) GetStoredCdrs(timeStart, timeEnd time.Time, ignoreErr, i
|
||||
}
|
||||
storCdr := &utils.StoredCdr{
|
||||
CgrId: cgrid, AccId: accid, CdrHost: cdrhost, CdrSource: cdrsrc, ReqType: reqtype, Direction: direction, Tenant: tenant,
|
||||
TOR: tor, Account: account, Subject: subject, Destination: destination, AnswerTime: answerTime, Duration: time.Duration(duration),
|
||||
TOR: tor, Account: account, Subject: subject, Destination: destination, SetupTime: setupTime, AnswerTime: answerTime, Duration: time.Duration(duration),
|
||||
ExtraFields: extraFieldsMp, MediationRunId: runid.String, Cost: cost.Float64,
|
||||
}
|
||||
cdrs = append(cdrs, storCdr)
|
||||
|
||||
@@ -52,7 +52,7 @@ type Mediator struct {
|
||||
func (self *Mediator) parseConfig() error {
|
||||
cfgVals := [][]string{self.cgrCfg.MediatorSubjectFields, self.cgrCfg.MediatorReqTypeFields, self.cgrCfg.MediatorDirectionFields,
|
||||
self.cgrCfg.MediatorTenantFields, self.cgrCfg.MediatorTORFields, self.cgrCfg.MediatorAccountFields, self.cgrCfg.MediatorDestFields,
|
||||
self.cgrCfg.MediatorAnswerTimeFields, self.cgrCfg.MediatorDurationFields}
|
||||
self.cgrCfg.MediatorSetupTimeFields, self.cgrCfg.MediatorAnswerTimeFields, self.cgrCfg.MediatorDurationFields}
|
||||
|
||||
// All other configured fields must match the length of reference fields
|
||||
for iCfgVal := range cfgVals {
|
||||
@@ -138,7 +138,8 @@ func (self *Mediator) RateCdr(dbcdr utils.RawCDR) error {
|
||||
for runIdx, runId := range self.cgrCfg.MediatorRunIds {
|
||||
forkedCdr, err := dbcdr.AsStoredCdr(self.cgrCfg.MediatorRunIds[runIdx], self.cgrCfg.MediatorReqTypeFields[runIdx], self.cgrCfg.MediatorDirectionFields[runIdx],
|
||||
self.cgrCfg.MediatorTenantFields[runIdx], self.cgrCfg.MediatorTORFields[runIdx], self.cgrCfg.MediatorAccountFields[runIdx],
|
||||
self.cgrCfg.MediatorSubjectFields[runIdx], self.cgrCfg.MediatorDestFields[runIdx], self.cgrCfg.MediatorAnswerTimeFields[runIdx],
|
||||
self.cgrCfg.MediatorSubjectFields[runIdx], self.cgrCfg.MediatorDestFields[runIdx],
|
||||
self.cgrCfg.MediatorSetupTimeFields[runIdx], self.cgrCfg.MediatorAnswerTimeFields[runIdx],
|
||||
self.cgrCfg.MediatorDurationFields[runIdx], []string{}, true)
|
||||
if err != nil { // Errors on fork, cannot calculate further, write that into db for later analysis
|
||||
self.cdrDb.SetRatedCdr(&utils.StoredCdr{CgrId: dbcdr.GetCgrId(), MediationRunId: runId, Cost: -1.0}, err.Error()) // Cannot fork CDR, important just runid and error
|
||||
|
||||
@@ -34,7 +34,7 @@ type Event interface {
|
||||
GetTOR(string) string
|
||||
GetTenant(string) string
|
||||
GetReqType(string) string
|
||||
GetStartTime(string) (time.Time, error)
|
||||
GetAnswerTime(string) (time.Time, error)
|
||||
GetEndTime() (time.Time, error)
|
||||
MissingParameter() bool
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ const (
|
||||
CSTMID = "variable_cgr_tenant"
|
||||
CALL_DEST_NR = "Caller-Destination-Number"
|
||||
PARK_TIME = "Caller-Profile-Created-Time"
|
||||
START_TIME = "Caller-Channel-Answered-Time"
|
||||
SETUP_TIME = "Caller-Channel-Created-Time"
|
||||
ANSWER_TIME = "Caller-Channel-Answered-Time"
|
||||
END_TIME = "Caller-Channel-Hangup-Time"
|
||||
NAME = "Event-Name"
|
||||
HEARTBEAT = "HEARTBEAT"
|
||||
@@ -120,7 +121,12 @@ func (fsev FSEvent) MissingParameter() bool {
|
||||
strings.TrimSpace(fsev.GetTenant("")) == "" ||
|
||||
strings.TrimSpace(fsev.GetCallDestNr("")) == ""
|
||||
}
|
||||
func (fsev FSEvent) GetStartTime(field string) (t time.Time, err error) {
|
||||
func (fsev FSEvent) GetSetupTime(field string) (t time.Time, err error) {
|
||||
st, err := strconv.ParseInt(fsev[field], 0, 64)
|
||||
t = time.Unix(0, st*1000)
|
||||
return
|
||||
}
|
||||
func (fsev FSEvent) GetAnswerTime(field string) (t time.Time, err error) {
|
||||
st, err := strconv.ParseInt(fsev[field], 0, 64)
|
||||
t = time.Unix(0, st*1000)
|
||||
return
|
||||
|
||||
@@ -151,7 +151,7 @@ func (sm *FSSessionManager) OnHeartBeat(ev Event) {
|
||||
|
||||
func (sm *FSSessionManager) OnChannelPark(ev Event) {
|
||||
//engine.Logger.Info("freeswitch park")
|
||||
startTime, err := ev.GetStartTime(PARK_TIME)
|
||||
startTime, err := ev.GetAnswerTime(PARK_TIME)
|
||||
if err != nil {
|
||||
engine.Logger.Err("Error parsing answer event start time, using time.Now!")
|
||||
startTime = time.Now()
|
||||
@@ -213,7 +213,7 @@ func (sm *FSSessionManager) OnChannelHangupComplete(ev Event) {
|
||||
}
|
||||
defer s.Close(ev) // Stop loop and save the costs deducted so far to database
|
||||
if ev.GetReqType("") == utils.POSTPAID {
|
||||
startTime, err := ev.GetStartTime(START_TIME)
|
||||
startTime, err := ev.GetAnswerTime(ANSWER_TIME)
|
||||
if err != nil {
|
||||
engine.Logger.Crit("Error parsing postpaid call start time from event")
|
||||
return
|
||||
|
||||
@@ -42,7 +42,7 @@ func NewSession(ev Event, sm SessionManager) (s *Session) {
|
||||
if ev.GetReqType("") != utils.PREPAID && ev.GetReqType("") != utils.POSTPAID {
|
||||
return
|
||||
}
|
||||
startTime, err := ev.GetStartTime(START_TIME)
|
||||
startTime, err := ev.GetAnswerTime(ANSWER_TIME)
|
||||
if err != nil {
|
||||
engine.Logger.Err("Error parsing answer event start time, using time.Now!")
|
||||
startTime = time.Now()
|
||||
|
||||
@@ -95,6 +95,9 @@ func (cgrCdr CgrCdr) GetExtraFields() map[string]string {
|
||||
}
|
||||
return extraFields
|
||||
}
|
||||
func (cgrCdr CgrCdr) GetSetupTime() (t time.Time, err error) {
|
||||
return ParseTimeDetectLayout(cgrCdr[SETUP_TIME])
|
||||
}
|
||||
func (cgrCdr CgrCdr) GetAnswerTime() (t time.Time, err error) {
|
||||
return ParseTimeDetectLayout(cgrCdr[ANSWER_TIME])
|
||||
}
|
||||
@@ -107,13 +110,13 @@ func (cgrCdr CgrCdr) GetDuration() time.Duration {
|
||||
|
||||
// Used in mediation, fieldsMandatory marks whether missing field out of request represents error or can be ignored
|
||||
// If the fields in parameters start with ^ their value is considered instead of dynamically retrieving it from CDR
|
||||
func (cgrCdr CgrCdr) AsStoredCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, answerTimeFld, durationFld string, extraFlds []string, fieldsMandatory bool) (*StoredCdr, error) {
|
||||
func (cgrCdr CgrCdr) AsStoredCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, setupTimeFld, answerTimeFld, durationFld string, extraFlds []string, fieldsMandatory bool) (*StoredCdr, error) {
|
||||
if IsSliceMember([]string{runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, answerTimeFld, durationFld}, "") {
|
||||
return nil, errors.New(fmt.Sprintf("%s:FieldName", ERR_MANDATORY_IE_MISSING)) // All input field names are mandatory
|
||||
}
|
||||
var err error
|
||||
var hasKey bool
|
||||
var aTimeStr, durStr string
|
||||
var sTimeStr, aTimeStr, durStr string
|
||||
rtCdr := new(StoredCdr)
|
||||
rtCdr.MediationRunId = runId
|
||||
rtCdr.Cost = -1.0 // Default for non-rated CDR
|
||||
@@ -167,6 +170,16 @@ func (cgrCdr CgrCdr) AsStoredCdr(runId, reqTypeFld, directionFld, tenantFld, tor
|
||||
} else if rtCdr.Destination, hasKey = cgrCdr[destFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, destFld))
|
||||
}
|
||||
if sTimeStr, hasKey = cgrCdr[setupTimeFld]; !hasKey && fieldsMandatory && !strings.HasPrefix(setupTimeFld, STATIC_VALUE_PREFIX) {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, setupTimeFld))
|
||||
} else {
|
||||
if strings.HasPrefix(setupTimeFld, STATIC_VALUE_PREFIX) {
|
||||
sTimeStr = setupTimeFld[1:]
|
||||
}
|
||||
if rtCdr.SetupTime, err = ParseTimeDetectLayout(sTimeStr); err != nil && fieldsMandatory {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if aTimeStr, hasKey = cgrCdr[answerTimeFld]; !hasKey && fieldsMandatory && !strings.HasPrefix(answerTimeFld, STATIC_VALUE_PREFIX) {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, answerTimeFld))
|
||||
} else {
|
||||
|
||||
@@ -80,30 +80,35 @@ func TestCgrCdrFields(t *testing.T) {
|
||||
|
||||
func TestCgrCdrAsStoredCdr(t *testing.T) {
|
||||
cgrCdr := &CgrCdr{"accid": "dsafdsaf", "cdrhost": "192.168.1.1", "cdrsource": "source_test", "reqtype": "rated", "direction": "*out", "tenant": "cgrates.org", "tor": "call",
|
||||
"account": "1001", "subject": "1001", "destination": "1002", "answer_time": "2013-11-07T08:42:26Z", "duration": "10",
|
||||
"account": "1001", "subject": "1001", "destination": "1002", "setup_time": "2013-11-07T08:42:24Z", "answer_time": "2013-11-07T08:42:26Z", "duration": "10",
|
||||
"field_extr1": "val_extr1", "fieldextr2": "valextr2"}
|
||||
rtCdrOut, err := cgrCdr.AsStoredCdr("wholesale_run", "reqtype", "direction", "tenant", "tor", "account", "subject", "destination", "answer_time", "duration", []string{"field_extr1", "fieldextr2"}, true)
|
||||
rtCdrOut, err := cgrCdr.AsStoredCdr("wholesale_run", "reqtype", "direction", "tenant", "tor", "account", "subject", "destination", "setup_time", "answer_time", "duration",
|
||||
[]string{"field_extr1", "fieldextr2"}, true)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error received", err)
|
||||
}
|
||||
expctRatedCdr := &StoredCdr{CgrId: FSCgrId("dsafdsaf"), AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "source_test", ReqType: "rated",
|
||||
Direction: "*out", Tenant: "cgrates.org", TOR: "call", Account: "1001", Subject: "1001", Destination: "1002", AnswerTime: time.Unix(1383813746, 0).UTC(),
|
||||
Direction: "*out", Tenant: "cgrates.org", TOR: "call", Account: "1001", Subject: "1001", Destination: "1002",
|
||||
SetupTime: time.Unix(1383813744, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(),
|
||||
Duration: 10000000000, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
if !reflect.DeepEqual(rtCdrOut, expctRatedCdr) {
|
||||
t.Errorf("Received: %v, expected: %v", rtCdrOut, expctRatedCdr)
|
||||
}
|
||||
rtCdrOut2, err := cgrCdr.AsStoredCdr("wholesale_run", "^postpaid", "^*in", "^cgrates.com", "^premium_call", "^first_account", "^first_subject", "destination", "^2013-12-07T08:42:26Z", "^12s", []string{"field_extr1", "fieldextr2"}, true)
|
||||
rtCdrOut2, err := cgrCdr.AsStoredCdr("wholesale_run", "^postpaid", "^*in", "^cgrates.com", "^premium_call", "^first_account", "^first_subject", "destination",
|
||||
"^2013-12-07T08:42:24Z", "^2013-12-07T08:42:26Z", "^12s", []string{"field_extr1", "fieldextr2"}, true)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error received", err)
|
||||
}
|
||||
expctRatedCdr2 := &StoredCdr{CgrId: FSCgrId("dsafdsaf"), AccId: "dsafdsaf", CdrHost: "192.168.1.1", CdrSource: "source_test", ReqType: "postpaid",
|
||||
Direction: "*in", Tenant: "cgrates.com", TOR: "premium_call", Account: "first_account", Subject: "first_subject", Destination: "1002",
|
||||
SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Duration: time.Duration(12) * time.Second,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, MediationRunId: "wholesale_run", Cost: -1}
|
||||
if !reflect.DeepEqual(rtCdrOut2, expctRatedCdr2) {
|
||||
t.Errorf("Received: %v, expected: %v", rtCdrOut2, expctRatedCdr2)
|
||||
}
|
||||
_, err = cgrCdr.AsStoredCdr("wholesale_run", "dummy_header", "direction", "tenant", "tor", "account", "subject", "destination", "answer_time", "duration", []string{"field_extr1", "fieldextr2"}, true)
|
||||
_, err = cgrCdr.AsStoredCdr("wholesale_run", "dummy_header", "direction", "tenant", "tor", "account", "subject", "destination", "setup_time", "answer_time", "duration",
|
||||
[]string{"field_extr1", "fieldextr2"}, true)
|
||||
if err == nil {
|
||||
t.Error("Failed to detect missing header")
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ const (
|
||||
ACCOUNT = "account"
|
||||
SUBJECT = "subject"
|
||||
DESTINATION = "destination"
|
||||
SETUP_TIME = "setup_time"
|
||||
ANSWER_TIME = "answer_time"
|
||||
DURATION = "duration"
|
||||
DEFAULT_RUNID = "default"
|
||||
|
||||
@@ -37,8 +37,9 @@ type RawCDR interface {
|
||||
GetTOR() string
|
||||
GetTenant() string
|
||||
GetReqType() string
|
||||
GetAnswerTime() (time.Time, error)
|
||||
GetSetupTime() (time.Time, error) // Time when the call was set-up
|
||||
GetAnswerTime() (time.Time, error) // Time when the call was answered
|
||||
GetDuration() time.Duration
|
||||
GetExtraFields() map[string]string //Stores extra CDR Fields
|
||||
AsStoredCdr(string, string, string, string, string, string, string, string, string, string, []string, bool) (*StoredCdr, error) // Based on fields queried will return a particular instance of RatedCDR
|
||||
GetExtraFields() map[string]string //Stores extra CDR Fields
|
||||
AsStoredCdr(string, string, string, string, string, string, string, string, string, string, string, []string, bool) (*StoredCdr, error) // Based on fields queried will return a particular instance of RatedCDR
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ func NewStoredCdrFromRawCDR(rawcdr RawCDR) (*StoredCdr, error) {
|
||||
rtCdr.Account = rawcdr.GetAccount()
|
||||
rtCdr.Subject = rawcdr.GetSubject()
|
||||
rtCdr.Destination = rawcdr.GetDestination()
|
||||
if rtCdr.SetupTime, err = rawcdr.GetSetupTime(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rtCdr.AnswerTime, err = rawcdr.GetAnswerTime(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -61,6 +64,7 @@ type StoredCdr struct {
|
||||
Account string
|
||||
Subject string
|
||||
Destination string
|
||||
SetupTime time.Time
|
||||
AnswerTime time.Time
|
||||
Duration time.Duration
|
||||
ExtraFields map[string]string
|
||||
@@ -114,6 +118,10 @@ func (storedCdr *StoredCdr) GetReqType() string {
|
||||
return storedCdr.ReqType
|
||||
}
|
||||
|
||||
func (storedCdr *StoredCdr) GetSetupTime() (time.Time, error) {
|
||||
return storedCdr.SetupTime, nil
|
||||
}
|
||||
|
||||
func (storedCdr *StoredCdr) GetAnswerTime() (time.Time, error) {
|
||||
return storedCdr.AnswerTime, nil
|
||||
}
|
||||
@@ -126,7 +134,7 @@ func (storedCdr *StoredCdr) GetExtraFields() map[string]string {
|
||||
return storedCdr.ExtraFields
|
||||
}
|
||||
|
||||
func (storedCdr *StoredCdr) AsStoredCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, answerTimeFld, durationFld string, extraFlds []string, fieldsMandatory bool) (*StoredCdr, error) {
|
||||
func (storedCdr *StoredCdr) AsStoredCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, setupTimeFld, answerTimeFld, durationFld string, extraFlds []string, fieldsMandatory bool) (*StoredCdr, error) {
|
||||
return storedCdr, nil
|
||||
}
|
||||
|
||||
@@ -143,6 +151,7 @@ func (storedCdr *StoredCdr) AsRawCdrHttpForm() url.Values {
|
||||
v.Set(ACCOUNT, storedCdr.Account)
|
||||
v.Set(SUBJECT, storedCdr.Subject)
|
||||
v.Set(DESTINATION, storedCdr.Destination)
|
||||
v.Set(SETUP_TIME, storedCdr.SetupTime.String())
|
||||
v.Set(ANSWER_TIME, storedCdr.AnswerTime.String())
|
||||
v.Set(DURATION, strconv.FormatFloat(storedCdr.Duration.Seconds(), 'f', -1, 64))
|
||||
for fld, val := range storedCdr.ExtraFields {
|
||||
|
||||
Reference in New Issue
Block a user