mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-17 06:09:53 +05:00
Adding static field values for multiple mediation in configuration, fmt on sources
This commit is contained in:
@@ -287,14 +287,20 @@ type AttrCacheStats struct { // Add in the future filters here maybe so we avoid
|
||||
}
|
||||
|
||||
type CacheStats struct {
|
||||
Destinations int
|
||||
RatingPlans int
|
||||
RatingProfiles int
|
||||
Actions int
|
||||
Destinations int
|
||||
RatingPlans int
|
||||
RatingProfiles int
|
||||
Actions int
|
||||
}
|
||||
|
||||
type AttrCachedItemAge struct {
|
||||
Category string // Item's category, same name as .csv files without extension
|
||||
ItemId string // Item's identity tag
|
||||
Category string // Item's category, same name as .csv files without extension
|
||||
ItemId string // Item's identity tag
|
||||
}
|
||||
|
||||
type CachedItemAge struct {
|
||||
Destination time.Duration
|
||||
RatingPlan time.Duration
|
||||
RatingProfile time.Duration
|
||||
Action time.Duration
|
||||
}
|
||||
|
||||
@@ -19,10 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package utils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NewCgrCdrFromHttpReq(req *http.Request) (CgrCdr, error) {
|
||||
@@ -105,10 +106,11 @@ func (cgrCdr CgrCdr) GetDuration() time.Duration {
|
||||
}
|
||||
|
||||
// Used in mediation, fieldsMandatory marks whether missing field out of request represents error or can be ignored
|
||||
func(cgrCdr CgrCdr) AsRatedCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, answerTimeFld, durationFld string, extraFlds []string, fieldsMandatory bool) (*RatedCDR, error) {
|
||||
// If the fields in parameters start with ^ their value is considered instead of dynamically retrieving it from CDR
|
||||
func (cgrCdr CgrCdr) AsRatedCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, answerTimeFld, durationFld string, extraFlds []string, fieldsMandatory bool) (*RatedCDR, 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
|
||||
@@ -130,37 +132,57 @@ func(cgrCdr CgrCdr) AsRatedCdr(runId, reqTypeFld, directionFld, tenantFld, torFl
|
||||
if rtCdr.CdrSource, hasKey = cgrCdr[CDRSOURCE]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, CDRSOURCE))
|
||||
}
|
||||
if rtCdr.ReqType, hasKey = cgrCdr[reqTypeFld]; !hasKey && fieldsMandatory {
|
||||
if strings.HasPrefix(reqTypeFld, STATIC_VALUE_PREFIX) { // Values starting with prefix are not dynamically populated
|
||||
rtCdr.ReqType = reqTypeFld[1:]
|
||||
} else if rtCdr.ReqType, hasKey = cgrCdr[reqTypeFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, reqTypeFld))
|
||||
}
|
||||
if rtCdr.Direction, hasKey = cgrCdr[directionFld]; !hasKey && fieldsMandatory {
|
||||
if strings.HasPrefix(directionFld, STATIC_VALUE_PREFIX) {
|
||||
rtCdr.Direction = directionFld[1:]
|
||||
} else if rtCdr.Direction, hasKey = cgrCdr[directionFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, directionFld))
|
||||
}
|
||||
if rtCdr.Tenant, hasKey = cgrCdr[tenantFld]; !hasKey && fieldsMandatory {
|
||||
if strings.HasPrefix(tenantFld, STATIC_VALUE_PREFIX) {
|
||||
rtCdr.Tenant = tenantFld[1:]
|
||||
} else if rtCdr.Tenant, hasKey = cgrCdr[tenantFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, tenantFld))
|
||||
}
|
||||
if rtCdr.TOR, hasKey = cgrCdr[torFld]; !hasKey && fieldsMandatory {
|
||||
if strings.HasPrefix(torFld, STATIC_VALUE_PREFIX) {
|
||||
rtCdr.TOR = torFld[1:]
|
||||
} else if rtCdr.TOR, hasKey = cgrCdr[torFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, torFld))
|
||||
}
|
||||
if rtCdr.Account, hasKey = cgrCdr[accountFld]; !hasKey && fieldsMandatory {
|
||||
if strings.HasPrefix(accountFld, STATIC_VALUE_PREFIX) {
|
||||
rtCdr.Account = accountFld[1:]
|
||||
} else if rtCdr.Account, hasKey = cgrCdr[accountFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, accountFld))
|
||||
}
|
||||
if rtCdr.Subject, hasKey = cgrCdr[subjectFld]; !hasKey && fieldsMandatory {
|
||||
if strings.HasPrefix(subjectFld, STATIC_VALUE_PREFIX) {
|
||||
rtCdr.Subject = subjectFld[1:]
|
||||
} else if rtCdr.Subject, hasKey = cgrCdr[subjectFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, subjectFld))
|
||||
}
|
||||
if rtCdr.Destination, hasKey = cgrCdr[destFld]; !hasKey && fieldsMandatory {
|
||||
if strings.HasPrefix(destFld, STATIC_VALUE_PREFIX) {
|
||||
rtCdr.Destination = destFld[1:]
|
||||
} else if rtCdr.Destination, hasKey = cgrCdr[destFld]; !hasKey && fieldsMandatory {
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, destFld))
|
||||
}
|
||||
if aTimeStr, hasKey = cgrCdr[answerTimeFld]; !hasKey && fieldsMandatory {
|
||||
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 {
|
||||
if strings.HasPrefix(answerTimeFld, STATIC_VALUE_PREFIX) {
|
||||
aTimeStr = answerTimeFld[1:]
|
||||
}
|
||||
if rtCdr.AnswerTime, err = ParseTimeDetectLayout(aTimeStr); err != nil && fieldsMandatory {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if durStr, hasKey = cgrCdr[durationFld]; !hasKey && fieldsMandatory {
|
||||
if durStr, hasKey = cgrCdr[durationFld]; !hasKey && fieldsMandatory && !strings.HasPrefix(durationFld, STATIC_VALUE_PREFIX){
|
||||
return nil, errors.New(fmt.Sprintf("%s:%s", ERR_MANDATORY_IE_MISSING, durationFld))
|
||||
} else {
|
||||
if strings.HasPrefix(durationFld, STATIC_VALUE_PREFIX) {
|
||||
durStr = durationFld[1:]
|
||||
}
|
||||
if rtCdr.Duration, err = ParseDurationWithSecs(durStr); err != nil && fieldsMandatory {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package utils
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -80,18 +80,31 @@ func TestCgrCdrFields(t *testing.T) {
|
||||
|
||||
func TestCgrCdrAsRatedCdr(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", "answer_time": "2013-11-07T08:42:26Z", "duration": "10",
|
||||
"field_extr1": "val_extr1", "fieldextr2": "valextr2"}
|
||||
rtCdrOut, err := cgrCdr.AsRatedCdr("wholesale_run", "reqtype", "direction", "tenant", "tor", "account", "subject", "destination", "answer_time", "duration", []string{"field_extr1","fieldextr2"}, true)
|
||||
rtCdrOut, err := cgrCdr.AsRatedCdr("wholesale_run", "reqtype", "direction", "tenant", "tor", "account", "subject", "destination", "answer_time", "duration", []string{"field_extr1", "fieldextr2"}, true)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error received", err)
|
||||
}
|
||||
expctRatedCdr := &RatedCDR{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(),
|
||||
Duration: 10000000000, ExtraFields: map[string]string{"field_extr1":"val_extr1", "fieldextr2": "valextr2"}, MediationRunId:"wholesale_run", Cost: -1}
|
||||
expctRatedCdr := &RatedCDR{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(),
|
||||
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.AsRatedCdr("wholesale_run", "^postpaid", "^*in", "^cgrates.com", "^premium_call", "^first_account", "^first_subject", "destination", "^2013-12-07T08:42:26Z", "^12s", []string{"field_extr1", "fieldextr2"}, true)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error received", err)
|
||||
}
|
||||
expctRatedCdr2 := &RatedCDR{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",
|
||||
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", rtCdrOut, expctRatedCdr)
|
||||
}
|
||||
_, err = cgrCdr.AsRatedCdr("wholesale_run", "dummy_header", "direction", "tenant", "tor", "account", "subject", "destination", "answer_time", "duration", []string{"field_extr1", "fieldextr2"}, true)
|
||||
if err == nil {
|
||||
t.Error("Failed to detect missing header")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -76,5 +76,6 @@ const (
|
||||
DESTINATION = "destination"
|
||||
ANSWER_TIME = "answer_time"
|
||||
DURATION = "duration"
|
||||
DEFAULT_RUNID = "default"
|
||||
DEFAULT_RUNID = "default"
|
||||
STATIC_VALUE_PREFIX = "^"
|
||||
)
|
||||
|
||||
@@ -22,13 +22,13 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"regexp"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Returns first non empty string out of vals. Useful to extract defaults
|
||||
@@ -113,8 +113,10 @@ func ParseTimeDetectLayout(tmStr string) (time.Time, error) {
|
||||
if tmstmp, err := strconv.ParseInt(tmStr, 10, 64); err != nil {
|
||||
return nilTime, err
|
||||
} else {
|
||||
return time.Unix(tmstmp,0), nil
|
||||
return time.Unix(tmstmp, 0), nil
|
||||
}
|
||||
case len(tmStr) == 0: // Time probably missing from request
|
||||
return nilTime, nil
|
||||
}
|
||||
return nilTime, errors.New("Unsupported time format")
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func NewRatedCDRFromRawCDR(rawcdr RawCDR) (*RatedCDR, error) {
|
||||
if rtCdr.AnswerTime, err = rawcdr.GetAnswerTime(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rtCdr.Duration = time.Duration(rawcdr.GetDuration()) * time.Second
|
||||
rtCdr.Duration = rawcdr.GetDuration()
|
||||
rtCdr.ExtraFields = rawcdr.GetExtraFields()
|
||||
rtCdr.MediationRunId = DEFAULT_RUNID
|
||||
rtCdr.Cost = -1
|
||||
@@ -69,59 +69,59 @@ type RatedCDR struct {
|
||||
// Methods maintaining RawCDR interface
|
||||
|
||||
func (ratedCdr *RatedCDR) GetCgrId() string {
|
||||
return ratedCdr.CgrId
|
||||
return ratedCdr.CgrId
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetAccId() string {
|
||||
return ratedCdr.AccId
|
||||
return ratedCdr.AccId
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetCdrHost() string {
|
||||
return ratedCdr.CdrHost
|
||||
return ratedCdr.CdrHost
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetCdrSource() string {
|
||||
return ratedCdr.CdrSource
|
||||
return ratedCdr.CdrSource
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetDirection() string {
|
||||
return ratedCdr.Direction
|
||||
return ratedCdr.Direction
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetSubject() string {
|
||||
return ratedCdr.Subject
|
||||
return ratedCdr.Subject
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetAccount() string {
|
||||
return ratedCdr.Account
|
||||
return ratedCdr.Account
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetDestination() string {
|
||||
return ratedCdr.Destination
|
||||
return ratedCdr.Destination
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetTOR() string {
|
||||
return ratedCdr.TOR
|
||||
return ratedCdr.TOR
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetTenant() string {
|
||||
return ratedCdr.Tenant
|
||||
return ratedCdr.Tenant
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetReqType() string {
|
||||
return ratedCdr.ReqType
|
||||
return ratedCdr.ReqType
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetAnswerTime() (time.Time, error) {
|
||||
return ratedCdr.AnswerTime, nil
|
||||
return ratedCdr.AnswerTime, nil
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetDuration() time.Duration {
|
||||
return ratedCdr.Duration
|
||||
return ratedCdr.Duration
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) GetExtraFields() map[string]string {
|
||||
return ratedCdr.ExtraFields
|
||||
return ratedCdr.ExtraFields
|
||||
}
|
||||
|
||||
func (ratedCdr *RatedCDR) AsRatedCdr(runId, reqTypeFld, directionFld, tenantFld, torFld, accountFld, subjectFld, destFld, answerTimeFld, durationFld string, extraFlds []string, fieldsMandatory bool) (*RatedCDR, error) {
|
||||
|
||||
@@ -21,6 +21,7 @@ package utils
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func TestRatedCDRInterfaces(t *testing.T) {
|
||||
@@ -29,11 +30,17 @@ func TestRatedCDRInterfaces(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewRatedCDRFromRawCDR(t *testing.T) {
|
||||
cgrCdr := CgrCdr{"accid": "dsafdsaf", "cdrhost": "192.168.1.1", "reqtype": "rated", "direction": "*out", "tenant": "cgrates.org", "tor": "call",
|
||||
"account": "1001", "subject": "1001", "destination": "1002", "answer_time": "2013-11-07T08:42:26Z", "duration": "10",
|
||||
cgrCdr := CgrCdr{"accid": "dsafdsaf", "cdrhost": "192.168.1.1", "cdrsource": "internal_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",
|
||||
"field_extr1": "val_extr1", "fieldextr2": "valextr2"}
|
||||
if _,err := NewRatedCDRFromRawCDR(cgrCdr); err != nil {
|
||||
expctRtCdr := &RatedCDR{CgrId: FSCgrId(cgrCdr["accid"]), AccId: cgrCdr["accid"], CdrHost: cgrCdr["cdrhost"], CdrSource: cgrCdr["cdrsource"], ReqType: cgrCdr["reqtype"],
|
||||
Direction: cgrCdr["direction"], Tenant: cgrCdr["tenant"], TOR: cgrCdr["tor"], Account: cgrCdr["account"], Subject: cgrCdr["subject"],
|
||||
Destination: cgrCdr["destination"], AnswerTime: time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC), Duration: time.Duration(10)*time.Second,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, MediationRunId: DEFAULT_RUNID, Cost: -1}
|
||||
if rt, err := NewRatedCDRFromRawCDR(cgrCdr); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(rt, expctRtCdr) {
|
||||
t.Errorf("Received %v, expected: %v", rt, expctRtCdr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +48,7 @@ func TestRatedCdrFields(t *testing.T) {
|
||||
ratedCdr := RatedCDR{CgrId: 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), Duration: 10,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
}
|
||||
}
|
||||
if ratedCdr.GetCgrId() != "b18944ef4dc618569f24c27b9872827a242bad0c" {
|
||||
t.Error("Error parsing cdr: ", ratedCdr)
|
||||
}
|
||||
|
||||
@@ -39,6 +39,6 @@ type RawCDR interface {
|
||||
GetReqType() string
|
||||
GetAnswerTime() (time.Time, error)
|
||||
GetDuration() time.Duration
|
||||
GetExtraFields() map[string]string //Stores extra CDR Fields
|
||||
GetExtraFields() map[string]string //Stores extra CDR Fields
|
||||
AsRatedCdr(string, string, string, string, string, string, string, string, string, string, []string, bool) (*RatedCDR, error) // Based on fields queried will return a particular instance of RatedCDR
|
||||
}
|
||||
|
||||
@@ -157,8 +157,6 @@ func TestParseTimeDetectLayout(t *testing.T) {
|
||||
t.Errorf("Expecting error")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func TestParseDateUnix(t *testing.T) {
|
||||
date, err := ParseDate("1375212790")
|
||||
|
||||
Reference in New Issue
Block a user