mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-16 05:39:54 +05:00
Adding initial xmlconfig structure with tests
This commit is contained in:
71
cdre/libfixedwidth.go
Normal file
71
cdre/libfixedwidth.go
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package cdre
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Used as generic function logic for various fields
|
||||
|
||||
// Attributes
|
||||
// source - the base source
|
||||
// maxLen - the maximum field lenght
|
||||
// stripAllowed - whether we allow stripping of chars in case of source bigger than the maximum allowed
|
||||
// lStrip - if true, strip from beginning of the string
|
||||
// lPadding - if true, add chars at the beginning of the string
|
||||
// paddingChar - the character wich will be used to fill the existing
|
||||
func filterField(source string, maxLen int, stripAllowed, lStrip, lPadding, padWithZero bool) (string, error) {
|
||||
if len(source) == maxLen { // the source is exactly the maximum length
|
||||
return source, nil
|
||||
}
|
||||
if len(source) > maxLen { //the source is bigger than allowed
|
||||
if !stripAllowed {
|
||||
return "", fmt.Errorf("source %s is bigger than the maximum allowed length %d", source, maxLen)
|
||||
}
|
||||
if !lStrip {
|
||||
return source[:maxLen], nil
|
||||
} else {
|
||||
diffIndx := len(source) - maxLen
|
||||
return source[diffIndx:], nil
|
||||
}
|
||||
} else { //the source is smaller as the maximum allowed
|
||||
paddingString := "%"
|
||||
if padWithZero {
|
||||
paddingString += "0" // it will not work for rPadding but this is not needed
|
||||
}
|
||||
if !lPadding {
|
||||
paddingString += "-"
|
||||
}
|
||||
paddingString += strconv.Itoa(maxLen) + "s"
|
||||
return fmt.Sprintf(paddingString, source), nil
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
type XmlCdreConfig struct {
|
||||
XMLName xml.Name `xml:"configuration"`
|
||||
Name string `xml:"name,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Header XMLFWCdrHeader `xml:"header"`
|
||||
Content XMLFWCdrContent `xml:"content"`
|
||||
Footer XMLFWCdrFooter `xml:"footer"`
|
||||
}
|
||||
*/
|
||||
103
config/xmlconfig.go
Normal file
103
config/xmlconfig.go
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Decodes a reader enforcing specific format of the configuration file
|
||||
func ParseCgrXmlConfig(reader io.Reader) (*CgrXmlCfgDocument, error) {
|
||||
xmlConfig := new(CgrXmlCfgDocument)
|
||||
decoder := xml.NewDecoder(reader)
|
||||
if err := decoder.Decode(xmlConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return xmlConfig, nil
|
||||
}
|
||||
|
||||
// Define a format for configuration file, one doc contains more configuration instances, identified by section, type and id
|
||||
type CgrXmlCfgDocument struct {
|
||||
XMLName xml.Name `xml:"document"`
|
||||
Type string `xml:"type,attr"`
|
||||
Configurations []*CgrXmlConfiguration `xml:"configuration"`
|
||||
}
|
||||
|
||||
// Storage for raw configuration
|
||||
type CgrXmlConfiguration struct {
|
||||
XMLName xml.Name `xml:"configuration"`
|
||||
Section string `xml:"section,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Id string `xml:"id,attr"`
|
||||
RawConfig []byte `xml:",innerxml"`
|
||||
}
|
||||
|
||||
// The CdrExporter Fixed Width configuration instance
|
||||
type CgrXmlCdreFwCfg struct {
|
||||
Header *CgrXmlCfgCdrHeader `xml:"header"`
|
||||
Content *CgrXmlCfgCdrContent `xml:"content"`
|
||||
Trailer *CgrXmlCfgCdrTrailer `xml:"trailer"`
|
||||
}
|
||||
|
||||
// CDR header
|
||||
type CgrXmlCfgCdrHeader struct {
|
||||
XMLName xml.Name `xml:"header"`
|
||||
Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
|
||||
}
|
||||
|
||||
// CDR content
|
||||
type CgrXmlCfgCdrContent struct {
|
||||
XMLName xml.Name `xml:"content"`
|
||||
Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
|
||||
}
|
||||
|
||||
// CDR trailer
|
||||
type CgrXmlCfgCdrTrailer struct {
|
||||
XMLName xml.Name `xml:"trailer"`
|
||||
Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
|
||||
}
|
||||
|
||||
// CDR field
|
||||
type CgrXmlCfgCdrField struct {
|
||||
XMLName xml.Name `xml:"field"`
|
||||
Name string `xml:"name,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Width string `xml:"width,attr"`
|
||||
}
|
||||
|
||||
func (xmlCfg *CgrXmlCfgDocument) GetCdreFWCfg(instName string) (*CgrXmlCdreFwCfg, error) {
|
||||
cdrefwCfg := new(CgrXmlCdreFwCfg)
|
||||
for _, cfgInst := range xmlCfg.Configurations {
|
||||
if cfgInst.Section != "cdre" || cfgInst.Type != utils.CDR_FIXED_WIDTH || cfgInst.Id != instName {
|
||||
continue
|
||||
}
|
||||
rawConfig := append([]byte("<element>"), cfgInst.RawConfig...)
|
||||
rawConfig = append(rawConfig, []byte("</element>")...)
|
||||
if err := xml.Unmarshal(rawConfig, cdrefwCfg); err != nil { // Encapsulate the rawConfig in one element so we can Unmarshall
|
||||
return nil, err
|
||||
} else if cdrefwCfg == nil {
|
||||
return nil, errors.New("Could not unmarshal CgrXmlCdreFwCfg")
|
||||
}
|
||||
return cdrefwCfg, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
108
config/xmlconfig_test.go
Normal file
108
config/xmlconfig_test.go
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2013 ITsysCOM
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var cfgDoc *CgrXmlCfgDocument // Will be populated by first test
|
||||
|
||||
func TestParseXmlConfig(t *testing.T) {
|
||||
cfgXmlStr := `<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<document type="cgrates/xml">
|
||||
<configuration section="cdre" type="cdr_fixed_width" id="CDRE-FW1">
|
||||
<header>
|
||||
<fields>
|
||||
<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" id="exportid" lpadding="true" padding_char="0" width="5"/>
|
||||
<field name="CutOffTime" type="metatag" id="time_lastcdr" layout="020106150400" width="12"/>
|
||||
<field name="FileCreationfTime" type="metatag" id="time_now" layout="020106150400" width="12"/>
|
||||
<field name="FileSpecificationVersion" type="constant" value="01" width="2"/>
|
||||
<field name="Filler2" type="filler" width="105"/>
|
||||
</fields>
|
||||
</header>
|
||||
<content>
|
||||
<fields>
|
||||
<field name="RecordType" type="constant" value="20" width="2"/>
|
||||
<field name="SIPTrunkID" type="cdrfield" id="cgrid" width="12"/>
|
||||
<field name="ConnectionNumber" type="cdrfield" id="subject" strip="left" padding="left" padding_char="0" width="5"/>
|
||||
<field name="ANumber" type="cdrfield" id="cli" strip="xright" width="15"/>
|
||||
<field name="CalledNumber" type="cdrfield" id="destination" strip="xright" width="24"/>
|
||||
<field name="ServiceType" type="constant" value="02" width="2"/>
|
||||
<field name="ServiceIdentification" type="constant" value="11" width="4"/>
|
||||
<field name="StartChargingDateTime" type="cdrfield" id="start_time" layout="020106150400" width="12"/>
|
||||
<field name="ChargeableTime" type="cdrfield" id="duration" width="6"/>
|
||||
<field name="DataVolume" type="filler" width="6"/>
|
||||
<field name="TaxCode" type="constant" value="1" width="1"/>
|
||||
<field name="OperatorTAPCode" type="cdrfield" id="opertapcode" width="2"/>
|
||||
<field name="ProductNumber" type="cdrfield" id="productnumber" width="5"/>
|
||||
<field name="NetworkSubtype" type="constant" value="3" width="1"/>
|
||||
<field name="SessionID" type="cdrfield" id="accid" width="16"/>
|
||||
<field name="VolumeUP" type="filler" width="8"/>
|
||||
<field name="VolumeDown" type="filler" width="8"/>
|
||||
<field name="TerminatingOperator" type="concatenated_cdrfield" id="tapcode,operatorcode" width="5"/>
|
||||
<field name="EndCharge" type="metatag" id="total_cost" lpadding="true" padding_char="0" width="9"/>
|
||||
<field name="CallMaskingIndicator" type="cdrfield" id="calledmask" width="1"/>
|
||||
</fields>
|
||||
</content>
|
||||
<trailer>
|
||||
<fields>
|
||||
<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" id="exportid" lpadding="true" padding_char="0" width="5"/>
|
||||
<field name="TotalNrRecords" type="metatag" id="nr_cdrs" lpadding="true" padding_char="0" width="6"/>
|
||||
<field name="TotalDurRecords" type="metatag" id="dur_cdrs" lpadding="true" padding_char="0" width="8"/>
|
||||
<field name="EarliestCDRTime" type="metatag" id="first_cdr_time" layout="020106150400" width="12"/>
|
||||
<field name="LatestCDRTime" type="metatag" id="last_cdr_time" layout="020106150400" width="12"/>
|
||||
<field name="Filler1" type="filler" width="93"/>
|
||||
</fields>
|
||||
</trailer>
|
||||
</configuration>
|
||||
</document>`
|
||||
var err error
|
||||
reader := strings.NewReader(cfgXmlStr)
|
||||
if cfgDoc, err = ParseCgrXmlConfig(reader); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if cfgDoc == nil {
|
||||
t.Fatal("Could not parse xml configuration document")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCdreFWCfg(t *testing.T) {
|
||||
cdreFWCfg, err := cfgDoc.GetCdreFWCfg("CDRE-FW1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else if cdreFWCfg == nil {
|
||||
t.Error("Could not parse CdreFw instance")
|
||||
}
|
||||
if len(cdreFWCfg.Header.Fields) != 8 {
|
||||
t.Error("Unexpected number of header fields parsed", len(cdreFWCfg.Header.Fields))
|
||||
}
|
||||
if len(cdreFWCfg.Content.Fields) != 20 {
|
||||
t.Error("Unexpected number of content fields parsed", len(cdreFWCfg.Content.Fields))
|
||||
}
|
||||
if len(cdreFWCfg.Trailer.Fields) != 9 {
|
||||
t.Error("Unexpected number of trailer fields parsed", len(cdreFWCfg.Trailer.Fields))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user