mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Adding ReSearchReplace struct
This commit is contained in:
@@ -84,32 +84,33 @@ type CGRConfig struct {
|
||||
RaterBalancer string // balancer address host:port
|
||||
BalancerEnabled bool
|
||||
SchedulerEnabled bool
|
||||
CDRSEnabled bool // Enable CDR Server service
|
||||
CDRSExtraFields []string // Extra fields to store in CDRs
|
||||
CDRSMediator string // Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
CdreCdrFormat string // Format of the exported CDRs. <csv>
|
||||
CdreExtraFields []string // Extra fields list to add in exported CDRs
|
||||
CdreDir string // Path towards exported cdrs directory
|
||||
CdrcEnabled bool // Enable CDR client functionality
|
||||
CdrcCdrs string // Address where to reach CDR server
|
||||
CdrcCdrsMethod string // Mechanism to use when posting CDRs on server <http_cgr>
|
||||
CdrcRunDelay time.Duration // Sleep interval between consecutive runs, if time unit missing, defaults to seconds, 0 to use automation via inotify
|
||||
CdrcCdrType string // CDR file format <csv>.
|
||||
CdrcCdrInDir string // Absolute path towards the directory where the CDRs are stored.
|
||||
CdrcCdrOutDir string // Absolute path towards the directory where processed CDRs will be moved.
|
||||
CdrcSourceId string // Tag identifying the source of the CDRs within CGRS database.
|
||||
CdrcAccIdField string // Accounting id field identifier. Use index number in case of .csv cdrs.
|
||||
CdrcReqTypeField string // Request type field identifier. Use index number in case of .csv cdrs.
|
||||
CdrcDirectionField string // Direction field identifier. Use index numbers in case of .csv cdrs.
|
||||
CdrcTenantField string // Tenant field identifier. Use index numbers in case of .csv cdrs.
|
||||
CdrcTorField string // Type of Record field identifier. Use index numbers in case of .csv cdrs.
|
||||
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"
|
||||
CDRSEnabled bool // Enable CDR Server service
|
||||
CDRSExtraFields []string // Extra fields to store in CDRs
|
||||
CDRSSearchReplaceRules map[string]*utils.ReSearchReplace // Key will be the field name, values their compiled ReSearchReplace rules
|
||||
CDRSMediator string // Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
CdreCdrFormat string // Format of the exported CDRs. <csv>
|
||||
CdreExtraFields []string // Extra fields list to add in exported CDRs
|
||||
CdreDir string // Path towards exported cdrs directory
|
||||
CdrcEnabled bool // Enable CDR client functionality
|
||||
CdrcCdrs string // Address where to reach CDR server
|
||||
CdrcCdrsMethod string // Mechanism to use when posting CDRs on server <http_cgr>
|
||||
CdrcRunDelay time.Duration // Sleep interval between consecutive runs, 0 to use automation via inotify
|
||||
CdrcCdrType string // CDR file format <csv>.
|
||||
CdrcCdrInDir string // Absolute path towards the directory where the CDRs are stored.
|
||||
CdrcCdrOutDir string // Absolute path towards the directory where processed CDRs will be moved.
|
||||
CdrcSourceId string // Tag identifying the source of the CDRs within CGRS database.
|
||||
CdrcAccIdField string // Accounting id field identifier. Use index number in case of .csv cdrs.
|
||||
CdrcReqTypeField string // Request type field identifier. Use index number in case of .csv cdrs.
|
||||
CdrcDirectionField string // Direction field identifier. Use index numbers in case of .csv cdrs.
|
||||
CdrcTenantField string // Tenant field identifier. Use index numbers in case of .csv cdrs.
|
||||
CdrcTorField string // Type of Record field identifier. Use index numbers in case of .csv cdrs.
|
||||
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 // Extra fields to extract, special format in case of .csv "field1:index1,field2:index2"
|
||||
SMEnabled bool
|
||||
SMSwitchType string
|
||||
SMRater string // address where to access rater. Can be internal, direct rater address or the address of a balancer
|
||||
|
||||
@@ -225,26 +225,3 @@ func ParseZeroRatingSubject(rateSubj string) (time.Duration, error) {
|
||||
durStr := rateSubj[len(ZERO_RATING_SUBJECT_PREFIX):]
|
||||
return time.ParseDuration(durStr)
|
||||
}
|
||||
|
||||
// Used to parse extra fields definition search regexp rule and replace template
|
||||
func ParseSearchReplaceStr(strRule string) (*regexp.Regexp, string, 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(strRule)
|
||||
if len(allMatches) != 3 { // Second and third groups are of interest to us
|
||||
return nil, "", errors.New("Invalid Search&Replace rule.")
|
||||
}
|
||||
searchRegexp, err := regexp.Compile(allMatches[1])
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return searchRegexp, allMatches[2], nil
|
||||
}
|
||||
|
||||
// Used to expand string sources, eg: extra fields
|
||||
func RegexpSearchReplace(src string, searchRgxp *regexp.Regexp, replaceTpl string) string {
|
||||
res := []byte{}
|
||||
match := searchRgxp.FindStringSubmatchIndex(src)
|
||||
res = searchRgxp.ExpandString(res, replaceTpl, src, match)
|
||||
return string(res)
|
||||
}
|
||||
|
||||
53
utils/researchreplace.go
Normal file
53
utils/researchreplace.go
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
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 utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Regexp Search/Replace, used for example for field formatting
|
||||
type ReSearchReplace struct {
|
||||
SearchRegexp *regexp.Regexp
|
||||
ReplaceTemplate string
|
||||
}
|
||||
|
||||
func (self *ReSearchReplace) Process(source string) string {
|
||||
res := []byte{}
|
||||
match := self.SearchRegexp.FindStringSubmatchIndex(source)
|
||||
res = self.SearchRegexp.ExpandString(res, self.ReplaceTemplate, source, match)
|
||||
return string(res)
|
||||
}
|
||||
|
||||
// Used to parse extra fields definition
|
||||
func ParseSearchReplaceFromFieldRule(fieldRule string) (string, *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, &ReSearchReplace{searchRegexp, allMatches[3]}, nil
|
||||
}
|
||||
63
utils/researchreplace_test.go
Normal file
63
utils/researchreplace_test.go
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
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 utils
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProcessReSearchReplace(t *testing.T) {
|
||||
rsr := &ReSearchReplace{regexp.MustCompile(`sip:\+49(\d+)@(\d*\.\d*\.\d*\.\d*)`), "0$1@$2"}
|
||||
source := "<sip:+4986517174963@127.0.0.1;transport=tcp>"
|
||||
expectOut := "086517174963@127.0.0.1"
|
||||
if outStr := rsr.Process(source); outStr != expectOut {
|
||||
t.Error("Unexpected output from SearchReplace: ", outStr)
|
||||
}
|
||||
}
|
||||
|
||||
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, &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, &ReSearchReplace{regexp.MustCompile(`sip:\+49(\d+)\/@`), "0$1"}) {
|
||||
t.Error("Unexpected ReSearchReplace parsed")
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package utils
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -387,46 +385,3 @@ func TestParseZeroRatingSubject(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSearchReplaceStr(t *testing.T) {
|
||||
// Normal case
|
||||
strRule := `~sip_redirected_to:s/sip:\+49(\d+)@/0$1/`
|
||||
srchRgxp, replaceTpl, err := ParseSearchReplaceStr(strRule)
|
||||
if srchRgxp == nil || len(replaceTpl) == 0 || err != nil {
|
||||
t.Error("Could not parse the str rule")
|
||||
} else if !reflect.DeepEqual(srchRgxp, regexp.MustCompile(`sip:\+49(\d+)@`)) {
|
||||
t.Error("Unexpected regexp search parsed")
|
||||
} else if replaceTpl != "0$1" {
|
||||
t.Error("Unexpected replace template parsed")
|
||||
}
|
||||
// Missing ~ prefix
|
||||
strRule = `sip_redirected_to:s/sip:\+49(\d+)@/0$1/`
|
||||
if _, _, err := ParseSearchReplaceStr(strRule); err == nil {
|
||||
t.Error("Parse error, srchrepl rule does not start with ~")
|
||||
}
|
||||
// Separator escaped
|
||||
strRule = `~sip_redirected_to:s\/sip:\+49(\d+)@/0$1/`
|
||||
if _, _, err := ParseSearchReplaceStr(strRule); err == nil {
|
||||
t.Error("Parse error, srchrepl rule does not contain correct number of separators")
|
||||
}
|
||||
// One extra separator but escaped
|
||||
strRule = `~sip_redirected_to:s/sip:\+49(\d+)\/@/0$1/`
|
||||
srchRgxp, replaceTpl, err = ParseSearchReplaceStr(strRule)
|
||||
if srchRgxp == nil || len(replaceTpl) == 0 || err != nil {
|
||||
t.Error("Could not parse the str rule")
|
||||
} else if !reflect.DeepEqual(srchRgxp, regexp.MustCompile(`sip:\+49(\d+)\/@`)) {
|
||||
t.Error("Unexpected regexp search parsed")
|
||||
} else if replaceTpl != "0$1" {
|
||||
t.Error("Unexpected replace template parsed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegexpSearchReplace(t *testing.T) {
|
||||
srchRgxp := regexp.MustCompile(`sip:\+49(\d+)@(\d*\.\d*\.\d*\.\d*)`)
|
||||
replaceTpl := "0$1@$2"
|
||||
source := "<sip:+4986517174963@127.0.0.1;transport=tcp>"
|
||||
expectOut := "086517174963@127.0.0.1"
|
||||
if outStr := RegexpSearchReplace(source, srchRgxp, replaceTpl); outStr != expectOut {
|
||||
t.Error("Unexpected output from SearchReplace: ", outStr)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user