mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Basic implementation of fixed_width cdr export content
This commit is contained in:
@@ -21,7 +21,6 @@ package config
|
||||
import (
|
||||
"code.google.com/p/goconf/conf"
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
@@ -46,22 +45,6 @@ func ConfigSlice(c *conf.ConfigFile, section, valName string) ([]string, error)
|
||||
return cfgValStrs, nil
|
||||
}
|
||||
|
||||
// Used to parse extra fields definition
|
||||
func parseSearchReplaceFromFieldRule(fieldRule string) (string, *utils.ReSearchReplace, error) {
|
||||
// String rule expected in the form ~hdr_name:s/match_rule/replace_rule/
|
||||
getRuleRgxp := regexp.MustCompile(`~(\w+):s\/(.+[^\\])\/(.+[^\\])\/`) // Make sure the separator / is not escaped in the rule
|
||||
allMatches := getRuleRgxp.FindStringSubmatch(fieldRule)
|
||||
if len(allMatches) != 4 { // Second and third groups are of interest to us
|
||||
return "", nil, errors.New("Invalid Search&Replace field rule.")
|
||||
}
|
||||
fieldName := allMatches[1]
|
||||
searchRegexp, err := regexp.Compile(allMatches[2])
|
||||
if err != nil {
|
||||
return fieldName, nil, err
|
||||
}
|
||||
return fieldName, &utils.ReSearchReplace{searchRegexp, allMatches[3]}, nil
|
||||
}
|
||||
|
||||
func ParseRSRFields(configVal string) ([]*utils.RSRField, error) {
|
||||
cfgValStrs := strings.Split(configVal, string(utils.CSV_SEP))
|
||||
if len(cfgValStrs) == 1 && cfgValStrs[0] == "" { // Prevents returning iterable with empty value
|
||||
@@ -73,14 +56,10 @@ func ParseRSRFields(configVal string) ([]*utils.RSRField, error) {
|
||||
return nil, errors.New("Empty values in config slice")
|
||||
|
||||
}
|
||||
if !strings.HasPrefix(cfgValStr, utils.REGEXP_SEP) {
|
||||
rsrFields[idx] = &utils.RSRField{Id: cfgValStr}
|
||||
continue // Nothing to be done for fields without ReSearchReplace rules
|
||||
}
|
||||
if fldId, reSrcRepl, err := parseSearchReplaceFromFieldRule(cfgValStr); err != nil {
|
||||
if rsrField, err := utils.NewRSRField(cfgValStr); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
rsrFields[idx] = &utils.RSRField{fldId, reSrcRepl}
|
||||
rsrFields[idx] = rsrField
|
||||
}
|
||||
}
|
||||
return rsrFields, nil
|
||||
|
||||
@@ -26,35 +26,6 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func TestParseSearchReplaceFromFieldRule(t *testing.T) {
|
||||
// Normal case
|
||||
fieldRule := `~sip_redirected_to:s/sip:\+49(\d+)@/0$1/`
|
||||
field, regSrchRplc, err := parseSearchReplaceFromFieldRule(fieldRule)
|
||||
if len(field) == 0 || regSrchRplc == nil || err != nil {
|
||||
t.Error("Failed parsing the field rule")
|
||||
} else if !reflect.DeepEqual(regSrchRplc, &utils.ReSearchReplace{regexp.MustCompile(`sip:\+49(\d+)@`), "0$1"}) {
|
||||
t.Error("Unexpected ReSearchReplace parsed")
|
||||
}
|
||||
// Missing ~ prefix
|
||||
fieldRule = `sip_redirected_to:s/sip:\+49(\d+)@/0$1/`
|
||||
if _, _, err := parseSearchReplaceFromFieldRule(fieldRule); err == nil {
|
||||
t.Error("Parse error, field rule does not start with ~")
|
||||
}
|
||||
// Separator escaped
|
||||
fieldRule = `~sip_redirected_to:s\/sip:\+49(\d+)@/0$1/`
|
||||
if _, _, err := parseSearchReplaceFromFieldRule(fieldRule); err == nil {
|
||||
t.Error("Parse error, field rule does not contain correct number of separators")
|
||||
}
|
||||
// One extra separator but escaped
|
||||
fieldRule = `~sip_redirected_to:s/sip:\+49(\d+)\/@/0$1/`
|
||||
field, regSrchRplc, err = parseSearchReplaceFromFieldRule(fieldRule)
|
||||
if len(field) == 0 || regSrchRplc == nil || err != nil {
|
||||
t.Error("Failed parsing the field rule")
|
||||
} else if !reflect.DeepEqual(regSrchRplc, &utils.ReSearchReplace{regexp.MustCompile(`sip:\+49(\d+)\/@`), "0$1"}) {
|
||||
t.Error("Unexpected ReSearchReplace parsed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRSRFields(t *testing.T) {
|
||||
fields := `host,~sip_redirected_to:s/sip:\+49(\d+)@/0$1/,destination`
|
||||
expectParsedFields := []*utils.RSRField{&utils.RSRField{Id: "host"},
|
||||
|
||||
@@ -79,15 +79,14 @@ type CgrXmlCfgCdrTrailer struct {
|
||||
|
||||
// CDR field
|
||||
type CgrXmlCfgCdrField struct {
|
||||
XMLName xml.Name `xml:"field"`
|
||||
Name string `xml:"name,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Value string `xml:"value,attr"`
|
||||
Width string `xml:"width,attr"`
|
||||
Strip string `xml:"strip,attr"`
|
||||
Padding string `xml:"padding,attr"`
|
||||
PaddingChar string `xml:"padding_char,attr"`
|
||||
Layout string `xml:"layout,attr"` // Eg. time format layout
|
||||
XMLName xml.Name `xml:"field"`
|
||||
Name string `xml:"name,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Value string `xml:"value,attr"`
|
||||
Width int `xml:"width,attr"` // Field width
|
||||
Strip string `xml:"strip,attr"` // Strip strategy in case value is bigger than field width <""|left|xleft|right|xright>
|
||||
Padding string `xml:"padding,attr"` // Padding strategy in case of value is smaller than width <""left|zeroleft|right>
|
||||
Layout string `xml:"layout,attr"` // Eg. time format layout
|
||||
}
|
||||
|
||||
// Avoid building from raw config string always, so build cache here
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestParseXmlConfig(t *testing.T) {
|
||||
<field name="RecordType" type="constant" value="10" width="2"/>
|
||||
<field name="Filler1" type="filler" width="3"/>
|
||||
<field name="NetworkProviderCode" type="constant" value="VOI" width="3"/>
|
||||
<field name="FileSeqNr" type="metatag" value="exportid" padding="left" padding_char="0" width="5"/>
|
||||
<field name="FileSeqNr" type="metatag" value="exportid" padding="zeroleft" width="5"/>
|
||||
<field name="CutOffTime" type="metatag" value="time_lastcdr" layout="020106150400" width="12"/>
|
||||
<field name="FileCreationfTime" type="metatag" value="time_now" layout="020106150400" width="12"/>
|
||||
<field name="FileSpecificationVersion" type="constant" value="01" width="2"/>
|
||||
@@ -45,7 +45,7 @@ func TestParseXmlConfig(t *testing.T) {
|
||||
<fields>
|
||||
<field name="RecordType" type="constant" value="20" width="2"/>
|
||||
<field name="SIPTrunkID" type="cdrfield" value="cgrid" width="12"/>
|
||||
<field name="ConnectionNumber" type="cdrfield" value="subject" strip="left" padding="left" padding_char="0" width="5"/>
|
||||
<field name="ConnectionNumber" type="cdrfield" value="subject" strip="left" padding="left" width="5"/>
|
||||
<field name="ANumber" type="cdrfield" value="cli" strip="xright" width="15"/>
|
||||
<field name="CalledNumber" type="cdrfield" value="destination" strip="xright" width="24"/>
|
||||
<field name="ServiceType" type="constant" value="02" width="2"/>
|
||||
@@ -61,7 +61,7 @@ func TestParseXmlConfig(t *testing.T) {
|
||||
<field name="VolumeUP" type="filler" width="8"/>
|
||||
<field name="VolumeDown" type="filler" width="8"/>
|
||||
<field name="TerminatingOperator" type="concatenated_cdrfield" value="tapcode,operatorcode" width="5"/>
|
||||
<field name="EndCharge" type="metatag" value="total_cost" padding="left" padding_char="0" width="9"/>
|
||||
<field name="EndCharge" type="cdrfield" value="cost" padding="zeroleft" width="9"/>
|
||||
<field name="CallMaskingIndicator" type="cdrfield" value="calledmask" width="1"/>
|
||||
</fields>
|
||||
</content>
|
||||
@@ -70,9 +70,9 @@ func TestParseXmlConfig(t *testing.T) {
|
||||
<field name="RecordType" type="constant" value="90" width="2"/>
|
||||
<field name="Filler1" type="filler" width="3"/>
|
||||
<field name="NetworkProviderCode" type="constant" value="VOI" width="3"/>
|
||||
<field name="FileSeqNr" type="metatag" value="exportid" padding="left" padding_char="0" width="5"/>
|
||||
<field name="TotalNrRecords" type="metatag" value="nr_cdrs" padding="left" padding_char="0" width="6"/>
|
||||
<field name="TotalDurRecords" type="metatag" value="dur_cdrs" padding="left" padding_char="0" width="8"/>
|
||||
<field name="FileSeqNr" type="metatag" value="exportid" padding="zeroleft" width="5"/>
|
||||
<field name="TotalNrRecords" type="metatag" value="nr_cdrs" padding="zeroleft" width="6"/>
|
||||
<field name="TotalDurRecords" type="metatag" value="dur_cdrs" padding="zeroleft" width="8"/>
|
||||
<field name="EarliestCDRTime" type="metatag" value="first_cdr_time" layout="020106150400" width="12"/>
|
||||
<field name="LatestCDRTime" type="metatag" value="last_cdr_time" layout="020106150400" width="12"/>
|
||||
<field name="Filler1" type="filler" width="93"/>
|
||||
|
||||
Reference in New Issue
Block a user