mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-24 16:48:45 +05:00
@@ -7,7 +7,7 @@ install:
|
||||
- go get github.com/Masterminds/glide
|
||||
- glide install
|
||||
|
||||
script: $TRAVIS_BUILD_DIR/test.sh
|
||||
script: go test -v $(glide novendor)
|
||||
|
||||
branches:
|
||||
only: master
|
||||
|
||||
@@ -42,6 +42,7 @@ information, please see the [`CONTRIBUTING.md`](CONTRIBUTING.md) file.
|
||||
| @bhepp | Brice Heppner |
|
||||
| @noahmehl | Noah Mehl |
|
||||
| @elfranne | Tom Braarup Cuykens |
|
||||
| @rbarrabe | Régis Barrabé |
|
||||
<!-- to sign, include a single line above this comment containing the following text:
|
||||
| @username | First Last |
|
||||
-->
|
||||
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
"github.com/fiorix/go-diameter/diam/sm"
|
||||
)
|
||||
|
||||
func NewDiameterAgent(cgrCfg *config.CGRConfig, smg *rpcclient.RpcClient, pubsubs *rpcclient.RpcClient) (*DiameterAgent, error) {
|
||||
func NewDiameterAgent(cgrCfg *config.CGRConfig, smg rpcclient.RpcClientConnection, pubsubs rpcclient.RpcClientConnection) (*DiameterAgent, error) {
|
||||
da := &DiameterAgent{cgrCfg: cgrCfg, smg: smg, pubsubs: pubsubs}
|
||||
dictsDir := cgrCfg.DiameterAgentCfg().DictionariesDir
|
||||
if len(dictsDir) != 0 {
|
||||
@@ -45,8 +45,8 @@ func NewDiameterAgent(cgrCfg *config.CGRConfig, smg *rpcclient.RpcClient, pubsub
|
||||
|
||||
type DiameterAgent struct {
|
||||
cgrCfg *config.CGRConfig
|
||||
smg *rpcclient.RpcClient // Connection towards CGR-SMG component
|
||||
pubsubs *rpcclient.RpcClient // Connection towards CGR-PubSub component
|
||||
smg rpcclient.RpcClientConnection // Connection towards CGR-SMG component
|
||||
pubsubs rpcclient.RpcClientConnection // Connection towards CGR-PubSub component
|
||||
}
|
||||
|
||||
// Creates the message handlers
|
||||
@@ -69,7 +69,7 @@ func (self *DiameterAgent) handlers() diam.Handler {
|
||||
return dSM
|
||||
}
|
||||
|
||||
func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestProcessor, cca *CCA) (bool, error) {
|
||||
func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestProcessor, processorVars map[string]string, cca *CCA) (bool, error) {
|
||||
passesAllFilters := true
|
||||
for _, fldFilter := range reqProcessor.RequestFilter {
|
||||
if passes, _ := passesFieldFilter(ccr.diamMessage, fldFilter, nil); !passes {
|
||||
@@ -122,7 +122,6 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro
|
||||
}
|
||||
}
|
||||
var maxUsage float64
|
||||
processorVars := make(map[string]string)
|
||||
processorVars[CGRResultCode] = strconv.Itoa(diam.Success)
|
||||
processorVars[CGRError] = ""
|
||||
if reqProcessor.DryRun { // DryRun does not send over network
|
||||
@@ -166,6 +165,15 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro
|
||||
processorVars[CGRResultCode] = strconv.Itoa(DiameterRatingFailed)
|
||||
}
|
||||
}
|
||||
if maxUsage < 0 {
|
||||
maxUsage = 0
|
||||
}
|
||||
if prevMaxUsageStr, hasKey := processorVars[CGRMaxUsage]; hasKey {
|
||||
prevMaxUsage, _ := strconv.ParseFloat(prevMaxUsageStr, 64)
|
||||
if prevMaxUsage < maxUsage {
|
||||
maxUsage = prevMaxUsage
|
||||
}
|
||||
}
|
||||
processorVars[CGRMaxUsage] = strconv.FormatFloat(maxUsage, 'f', -1, 64)
|
||||
}
|
||||
if err := messageSetAVPsWithPath(cca.diamMessage, []interface{}{"Result-Code"}, processorVars[CGRResultCode],
|
||||
@@ -190,10 +198,14 @@ func (self *DiameterAgent) handleCCR(c diam.Conn, m *diam.Message) {
|
||||
return
|
||||
}
|
||||
cca := NewBareCCAFromCCR(ccr, self.cgrCfg.DiameterAgentCfg().OriginHost, self.cgrCfg.DiameterAgentCfg().OriginRealm)
|
||||
var processed bool
|
||||
var processed, lclProcessed bool
|
||||
processorVars := make(map[string]string) // Shared between processors
|
||||
for _, reqProcessor := range self.cgrCfg.DiameterAgentCfg().RequestProcessors {
|
||||
processed, err = self.processCCR(ccr, reqProcessor, cca)
|
||||
if err != nil || (processed && !reqProcessor.ContinueOnSuccess) {
|
||||
lclProcessed, err = self.processCCR(ccr, reqProcessor, processorVars, cca)
|
||||
if lclProcessed { // Process local so we don't overwrite globally
|
||||
processed = lclProcessed
|
||||
}
|
||||
if err != nil || (lclProcessed && !reqProcessor.ContinueOnSuccess) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ func TestDmtAgentTPFromFolder(t *testing.T) {
|
||||
if err := apierRpc.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &loadInst); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
time.Sleep(time.Duration(1000) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
func TestConnectDiameterClient(t *testing.T) {
|
||||
@@ -242,7 +242,7 @@ func TestDmtAgentSendCCRInit(t *testing.T) {
|
||||
if err := dmtClient.SendMessage(m); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(100) * time.Millisecond)
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
msg := dmtClient.ReceivedMessage()
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Granted-Service-Unit", "CC-Time"}, dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
@@ -286,7 +286,7 @@ func TestDmtAgentSendCCRUpdate(t *testing.T) {
|
||||
if err := dmtClient.SendMessage(m); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(100) * time.Millisecond)
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
msg := dmtClient.ReceivedMessage()
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Granted-Service-Unit", "CC-Time"}, dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
@@ -325,7 +325,7 @@ func TestDmtAgentSendCCRUpdate2(t *testing.T) {
|
||||
if err := dmtClient.SendMessage(m); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(100) * time.Millisecond)
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
msg := dmtClient.ReceivedMessage()
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Granted-Service-Unit", "CC-Time"}, dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
@@ -363,7 +363,7 @@ func TestDmtAgentSendCCRTerminate(t *testing.T) {
|
||||
if err := dmtClient.SendMessage(m); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(150) * time.Millisecond)
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
msg := dmtClient.ReceivedMessage()
|
||||
if msg == nil {
|
||||
t.Fatal("No answer to CCR terminate received")
|
||||
@@ -626,7 +626,7 @@ func TestDmtAgentSendCCRSimpaEvent(t *testing.T) {
|
||||
}),
|
||||
diam.NewAVP(29000, avp.Mbit, 2011, &diam.GroupedAVP{ // MC-Information
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(29001, avp.Mbit, 2011, datatype.OctetString("0x38924012914528")), // HighLayerCharacteristics
|
||||
diam.NewAVP(20938, avp.Mbit, 2011, datatype.OctetString("0x38924012914528")), // HighLayerCharacteristics
|
||||
diam.NewAVP(29002, avp.Mbit, 2011, datatype.UTF8String("12928471313847173")), // MC-Service-Id
|
||||
diam.NewAVP(29003, avp.Mbit, 2011, datatype.UTF8String("SPV123456012123")), // TransparentData
|
||||
diam.NewAVP(1201, avp.Mbit, 10415, &diam.GroupedAVP{ // MC-Information
|
||||
@@ -641,7 +641,7 @@ func TestDmtAgentSendCCRSimpaEvent(t *testing.T) {
|
||||
if err := dmtClient.SendMessage(ccr); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(100) * time.Millisecond)
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
msg := dmtClient.ReceivedMessage() // Discard the received message so we can test next one
|
||||
if msg == nil {
|
||||
t.Fatal("No message returned")
|
||||
@@ -675,6 +675,261 @@ func TestDmtAgentCdrs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDmtAgentSendDataGrpInit(t *testing.T) {
|
||||
if !*testIntegration {
|
||||
return
|
||||
}
|
||||
ccr := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("testdatagrp"))
|
||||
ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
|
||||
ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
|
||||
ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
|
||||
ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("gprs@huawei.com"))
|
||||
ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(1))
|
||||
ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(1))
|
||||
ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2016, 1, 5, 11, 30, 10, 0, time.UTC)))
|
||||
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(0)),
|
||||
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("1001")), // Subscription-Id-Data
|
||||
}})
|
||||
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(1)),
|
||||
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("104502200011")), // Subscription-Id-Data
|
||||
}})
|
||||
ccr.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0))
|
||||
ccr.NewAVP(avp.RequestedAction, avp.Mbit, 0, datatype.Enumerated(0))
|
||||
ccr.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(1))}})
|
||||
ccr.NewAVP(873, avp.Mbit, 10415, &diam.GroupedAVP{ //
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String("22509")), // Calling-Vlr-Number
|
||||
diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("4002")), // Called-Party-NP
|
||||
},
|
||||
}),
|
||||
diam.NewAVP(2000, avp.Mbit, 10415, &diam.GroupedAVP{ // SMS-Information
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(886, avp.Mbit, 10415, &diam.GroupedAVP{ // Originator-Address
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
|
||||
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1003")), // Address-Data
|
||||
}}),
|
||||
diam.NewAVP(1201, avp.Mbit, 10415, &diam.GroupedAVP{ // Recipient-Address
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
|
||||
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1002")), // Address-Data
|
||||
}}),
|
||||
},
|
||||
}),
|
||||
}})
|
||||
if err := dmtClient.SendMessage(ccr); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
msg := dmtClient.ReceivedMessage()
|
||||
if msg == nil {
|
||||
t.Fatal("No message returned")
|
||||
}
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Result-Code"}, dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(avps) == 0 {
|
||||
t.Error("Result-Code not found")
|
||||
} else if resCode := avpValAsString(avps[0]); resCode != "2001" {
|
||||
t.Errorf("Expecting 2001, received: %s", resCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDmtAgentSendDataGrpUpdate(t *testing.T) {
|
||||
if !*testIntegration {
|
||||
return
|
||||
}
|
||||
ccr := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("testdatagrp"))
|
||||
ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
|
||||
ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
|
||||
ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
|
||||
ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("gprs@huawei.com"))
|
||||
ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(2))
|
||||
ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(1))
|
||||
ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2016, 1, 5, 11, 30, 10, 0, time.UTC)))
|
||||
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(0)),
|
||||
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("1001")), // Subscription-Id-Data
|
||||
}})
|
||||
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(1)),
|
||||
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("104502200011")), // Subscription-Id-Data
|
||||
}})
|
||||
ccr.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0))
|
||||
ccr.NewAVP(avp.RequestedAction, avp.Mbit, 0, datatype.Enumerated(0))
|
||||
ccr.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(1))}})
|
||||
ccr.NewAVP(873, avp.Mbit, 10415, &diam.GroupedAVP{ //
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String("22509")), // Calling-Vlr-Number
|
||||
diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("4002")), // Called-Party-NP
|
||||
},
|
||||
}),
|
||||
diam.NewAVP(2000, avp.Mbit, 10415, &diam.GroupedAVP{ // SMS-Information
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(886, avp.Mbit, 10415, &diam.GroupedAVP{ // Originator-Address
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
|
||||
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1003")), // Address-Data
|
||||
}}),
|
||||
diam.NewAVP(1201, avp.Mbit, 10415, &diam.GroupedAVP{ // Recipient-Address
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
|
||||
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1002")), // Address-Data
|
||||
}}),
|
||||
},
|
||||
}),
|
||||
}})
|
||||
ccr.NewAVP("Multiple-Services-Credit-Control", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(446, avp.Mbit, 0, &diam.GroupedAVP{ // Used-Service-Unit
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(452, avp.Mbit, 0, datatype.Enumerated(0)), // Tariff-Change-Usage
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(20)), // CC-Time
|
||||
diam.NewAVP(412, avp.Mbit, 0, datatype.Unsigned64(1000)), // CC-Input-Octets
|
||||
diam.NewAVP(414, avp.Mbit, 0, datatype.Unsigned64(24)), // CC-Output-Octets
|
||||
},
|
||||
}),
|
||||
diam.NewAVP(432, avp.Mbit, 0, datatype.Unsigned32(1)), // Data session for group 1
|
||||
},
|
||||
})
|
||||
ccr.NewAVP("Multiple-Services-Credit-Control", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(446, avp.Mbit, 0, &diam.GroupedAVP{ // Used-Service-Unit
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(452, avp.Mbit, 0, datatype.Enumerated(0)), // Tariff-Change-Usage
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(20)), // CC-Time
|
||||
diam.NewAVP(412, avp.Mbit, 0, datatype.Unsigned64(1024)), // CC-Input-Octets
|
||||
diam.NewAVP(414, avp.Mbit, 0, datatype.Unsigned64(512)), // CC-Output-Octets
|
||||
},
|
||||
}),
|
||||
diam.NewAVP(432, avp.Mbit, 0, datatype.Unsigned32(2)), // Data session for group 2
|
||||
},
|
||||
})
|
||||
if err := dmtClient.SendMessage(ccr); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
msg := dmtClient.ReceivedMessage()
|
||||
if msg == nil {
|
||||
t.Fatal("No message returned")
|
||||
}
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Result-Code"}, dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(avps) == 0 {
|
||||
t.Error("Result-Code not found")
|
||||
} else if resCode := avpValAsString(avps[0]); resCode != "2001" {
|
||||
t.Errorf("Expecting 2001, received: %s", resCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDmtAgentSendDataGrpTerminate(t *testing.T) {
|
||||
if !*testIntegration {
|
||||
return
|
||||
}
|
||||
ccr := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("testdatagrp"))
|
||||
ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
|
||||
ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
|
||||
ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
|
||||
ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("gprs@huawei.com"))
|
||||
ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(3))
|
||||
ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(1))
|
||||
ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2016, 1, 5, 11, 30, 10, 0, time.UTC)))
|
||||
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(0)),
|
||||
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("1001")), // Subscription-Id-Data
|
||||
}})
|
||||
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(1)),
|
||||
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("104502200011")), // Subscription-Id-Data
|
||||
}})
|
||||
ccr.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0))
|
||||
ccr.NewAVP(avp.RequestedAction, avp.Mbit, 0, datatype.Enumerated(0))
|
||||
ccr.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(1))}})
|
||||
ccr.NewAVP(873, avp.Mbit, 10415, &diam.GroupedAVP{ //
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String("22509")), // Calling-Vlr-Number
|
||||
diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("4002")), // Called-Party-NP
|
||||
},
|
||||
}),
|
||||
diam.NewAVP(2000, avp.Mbit, 10415, &diam.GroupedAVP{ // SMS-Information
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(886, avp.Mbit, 10415, &diam.GroupedAVP{ // Originator-Address
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
|
||||
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1003")), // Address-Data
|
||||
}}),
|
||||
diam.NewAVP(1201, avp.Mbit, 10415, &diam.GroupedAVP{ // Recipient-Address
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
|
||||
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1002")), // Address-Data
|
||||
}}),
|
||||
},
|
||||
}),
|
||||
}})
|
||||
ccr.NewAVP("Multiple-Services-Credit-Control", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(446, avp.Mbit, 0, &diam.GroupedAVP{ // Used-Service-Unit
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(452, avp.Mbit, 0, datatype.Enumerated(0)), // Tariff-Change-Usage
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(20)), // CC-Time
|
||||
diam.NewAVP(412, avp.Mbit, 0, datatype.Unsigned64(512)), // CC-Input-Octets
|
||||
diam.NewAVP(414, avp.Mbit, 0, datatype.Unsigned64(0)), // CC-Output-Octets
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
if err := dmtClient.SendMessage(ccr); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(3000) * time.Millisecond)
|
||||
msg := dmtClient.ReceivedMessage()
|
||||
if msg == nil {
|
||||
t.Fatal("No message returned")
|
||||
}
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Result-Code"}, dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(avps) == 0 {
|
||||
t.Error("Result-Code not found")
|
||||
} else if resCode := avpValAsString(avps[0]); resCode != "2001" {
|
||||
t.Errorf("Expecting 2001, received: %s", resCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDmtAgentSendDataGrpCDRs(t *testing.T) {
|
||||
if !*testIntegration {
|
||||
return
|
||||
}
|
||||
var cdrs []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{CGRIDs: []string{utils.Sha1("testdatagrp")}}
|
||||
if err := apierRpc.Call("ApierV2.GetCdrs", req, &cdrs); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(cdrs) != 3 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(cdrs))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDmtAgentDryRun1(t *testing.T) {
|
||||
if !*testIntegration {
|
||||
return
|
||||
|
||||
124
agents/hapool_it_test.go
Normal file
124
agents/hapool_it_test.go
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can Storagetribute 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 WITH*out 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 agents
|
||||
|
||||
/*
|
||||
import (
|
||||
"os/exec"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
)
|
||||
|
||||
var cgrRater1Cmd, cgrSmg1Cmd *exec.Cmd
|
||||
|
||||
func TestHaPoolInitCfg(t *testing.T) {
|
||||
if !*testIntegration {
|
||||
return
|
||||
}
|
||||
daCfgPath = path.Join(*dataDir, "conf", "samples", "hapool", "cgrrater1")
|
||||
// Init config first
|
||||
var err error
|
||||
daCfg, err = config.NewCGRConfigFromFolder(daCfgPath)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
daCfg.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(daCfg)
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func TestHaPoolResetDataDb(t *testing.T) {
|
||||
TestDmtAgentResetDataDb(t)
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func TestHaPoolResetStorDb(t *testing.T) {
|
||||
TestDmtAgentResetStorDb(t)
|
||||
}
|
||||
|
||||
// Start CGR Engine
|
||||
func TestHaPoolStartEngine(t *testing.T) {
|
||||
if !*testIntegration {
|
||||
return
|
||||
}
|
||||
engine.KillEngine(*waitRater) // just to make sure
|
||||
var err error
|
||||
cgrRater1 := path.Join(*dataDir, "conf", "samples", "hapool", "cgrrater1")
|
||||
if cgrRater1Cmd, err = engine.StartEngine(cgrRater1, *waitRater); err != nil {
|
||||
t.Fatal("cgrRater1: ", err)
|
||||
}
|
||||
cgrRater2 := path.Join(*dataDir, "conf", "samples", "hapool", "cgrrater2")
|
||||
if _, err = engine.StartEngine(cgrRater2, *waitRater); err != nil {
|
||||
t.Fatal("cgrRater2: ", err)
|
||||
}
|
||||
cgrSmg1 := path.Join(*dataDir, "conf", "samples", "hapool", "cgrsmg1")
|
||||
if cgrSmg1Cmd, err = engine.StartEngine(cgrSmg1, *waitRater); err != nil {
|
||||
t.Fatal("cgrSmg1: ", err)
|
||||
}
|
||||
cgrSmg2 := path.Join(*dataDir, "conf", "samples", "hapool", "cgrsmg2")
|
||||
if _, err = engine.StartEngine(cgrSmg2, *waitRater); err != nil {
|
||||
t.Fatal("cgrSmg2: ", err)
|
||||
}
|
||||
cgrDa := path.Join(*dataDir, "conf", "samples", "hapool", "dagent")
|
||||
if _, err = engine.StartEngine(cgrDa, *waitRater); err != nil {
|
||||
t.Fatal("cgrDa: ", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestHaPoolApierRpcConn(t *testing.T) {
|
||||
TestDmtAgentApierRpcConn(t)
|
||||
}
|
||||
|
||||
// Load the tariff plan, creating accounts and their balances
|
||||
func TestHaPoolTPFromFolder(t *testing.T) {
|
||||
TestDmtAgentTPFromFolder(t)
|
||||
}
|
||||
|
||||
// cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:47:26Z"'
|
||||
func TestHaPoolSendCCRInit(t *testing.T) {
|
||||
TestDmtAgentSendCCRInit(t)
|
||||
}
|
||||
|
||||
// cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:52:26Z"'
|
||||
func TestHaPoolSendCCRUpdate(t *testing.T) {
|
||||
TestDmtAgentSendCCRUpdate(t)
|
||||
}
|
||||
|
||||
// cgr-console 'cost Category="call" Tenant="cgrates.org" Subject="1001" Destination="1004" TimeStart="2015-11-07T08:42:26Z" TimeEnd="2015-11-07T08:57:26Z"'
|
||||
func TestHaPoolSendCCRUpdate2(t *testing.T) {
|
||||
TestDmtAgentSendCCRUpdate2(t)
|
||||
}
|
||||
|
||||
func TestHaPoolSendCCRTerminate(t *testing.T) {
|
||||
TestDmtAgentSendCCRTerminate(t)
|
||||
}
|
||||
|
||||
func TestHaPoolCdrs(t *testing.T) {
|
||||
TestDmtAgentCdrs(t)
|
||||
}
|
||||
|
||||
func TestHaPoolStopEngine(t *testing.T) {
|
||||
TestDmtAgentStopEngine(t)
|
||||
}
|
||||
*/
|
||||
@@ -244,8 +244,8 @@ func metaValueExponent(m *diam.Message, argsTpl utils.RSRFields, roundingDecimal
|
||||
return strconv.FormatFloat(utils.Round(res, roundingDecimals, utils.ROUNDING_MIDDLE), 'f', -1, 64), nil
|
||||
}
|
||||
|
||||
func metaSum(m *diam.Message, argsTpl utils.RSRFields, roundingDecimals int) (string, error) {
|
||||
valStr := composedFieldvalue(m, argsTpl, 0, nil)
|
||||
func metaSum(m *diam.Message, argsTpl utils.RSRFields, passAtIndex, roundingDecimals int) (string, error) {
|
||||
valStr := composedFieldvalue(m, argsTpl, passAtIndex, nil)
|
||||
handlerArgs := strings.Split(valStr, utils.HandlerArgSep)
|
||||
var summed float64
|
||||
for _, arg := range handlerArgs {
|
||||
@@ -287,6 +287,11 @@ func passesFieldFilter(m *diam.Message, fieldFilter *utils.RSRField, processorVa
|
||||
if err != nil {
|
||||
return false, 0
|
||||
}
|
||||
if len(avps) == 0 { // No AVP found in request, treat it same as empty
|
||||
if fieldFilter.FilterPasses("") {
|
||||
return true, -1
|
||||
}
|
||||
}
|
||||
for avpIdx, avpVal := range avps { // First match wins due to index
|
||||
if fieldFilter.FilterPasses(avpValAsString(avpVal)) {
|
||||
return true, avpIdx
|
||||
@@ -398,7 +403,7 @@ func fieldOutVal(m *diam.Message, cfgFld *config.CfgCdrField, extraParam interfa
|
||||
case META_VALUE_EXPONENT:
|
||||
outVal, err = metaValueExponent(m, cfgFld.Value, 10) // FixMe: add here configured number of decimals
|
||||
case META_SUM:
|
||||
outVal, err = metaSum(m, cfgFld.Value, 10)
|
||||
outVal, err = metaSum(m, cfgFld.Value, passAtIndex, 10)
|
||||
default:
|
||||
outVal, err = metaHandler(m, cfgFld.HandlerId, cfgFld.Layout, extraParam.(time.Duration))
|
||||
if err != nil {
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/sessionmanager"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/fiorix/go-diameter/diam"
|
||||
"github.com/fiorix/go-diameter/diam/avp"
|
||||
@@ -133,12 +134,12 @@ func TestMetaSum(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
})
|
||||
if val, err := metaSum(m, utils.ParseRSRFieldsMustCompile("Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;^|;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", utils.INFIELD_SEP), 10); err != nil {
|
||||
if val, err := metaSum(m, utils.ParseRSRFieldsMustCompile("Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;^|;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", utils.INFIELD_SEP), 0, 10); err != nil {
|
||||
t.Error(err)
|
||||
} else if val != "9995" {
|
||||
t.Error("Received: ", val)
|
||||
}
|
||||
if _, err = metaSum(m, utils.ParseRSRFieldsMustCompile("Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", utils.INFIELD_SEP), 10); err == nil {
|
||||
if _, err = metaSum(m, utils.ParseRSRFieldsMustCompile("Requested-Service-Unit>CC-Money>Unit-Value>Value-Digits;Requested-Service-Unit>CC-Money>Unit-Value>Exponent", utils.INFIELD_SEP), 0, 10); err == nil {
|
||||
t.Error("Should have received error") // Insufficient number arguments
|
||||
}
|
||||
}
|
||||
@@ -396,3 +397,86 @@ func TestCCASetProcessorAVPs(t *testing.T) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eMessage, ccaMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCCRAsSMGenericEvent(t *testing.T) {
|
||||
ccr := &CCR{ // Bare information, just the one needed for answer
|
||||
SessionId: "ccrasgen1",
|
||||
AuthApplicationId: 4,
|
||||
CCRequestType: 3,
|
||||
}
|
||||
ccr.diamMessage = ccr.AsBareDiameterMessage()
|
||||
ccr.diamMessage.NewAVP("Multiple-Services-Credit-Control", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(446, avp.Mbit, 0, &diam.GroupedAVP{ // Used-Service-Unit
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(17)), // CC-Time
|
||||
diam.NewAVP(412, avp.Mbit, 0, datatype.Unsigned64(1341)), // CC-Input-Octets
|
||||
diam.NewAVP(414, avp.Mbit, 0, datatype.Unsigned64(3079)), // CC-Output-Octets
|
||||
},
|
||||
}),
|
||||
diam.NewAVP(432, avp.Mbit, 0, datatype.Unsigned32(99)),
|
||||
},
|
||||
})
|
||||
ccr.diamMessage.NewAVP("Multiple-Services-Credit-Control", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(446, avp.Mbit, 0, &diam.GroupedAVP{ // Used-Service-Unit
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(452, avp.Mbit, 0, datatype.Enumerated(0)), // Tariff-Change-Usage
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(20)), // CC-Time
|
||||
diam.NewAVP(412, avp.Mbit, 0, datatype.Unsigned64(8046)), // CC-Input-Octets
|
||||
diam.NewAVP(414, avp.Mbit, 0, datatype.Unsigned64(46193)), // CC-Output-Octets
|
||||
},
|
||||
}),
|
||||
diam.NewAVP(432, avp.Mbit, 0, datatype.Unsigned32(1)),
|
||||
},
|
||||
})
|
||||
ccr.diamMessage.NewAVP("FramedIPAddress", avp.Mbit, 0, datatype.OctetString("0AE40041"))
|
||||
cfgFlds := make([]*config.CfgCdrField, 0)
|
||||
eSMGEv := sessionmanager.SMGenericEvent{"EventName": "DIAMETER_CCR"}
|
||||
if rSMGEv, err := ccr.AsSMGenericEvent(cfgFlds); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eSMGEv, rSMGEv) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSMGEv, rSMGEv)
|
||||
}
|
||||
cfgFlds = []*config.CfgCdrField{
|
||||
&config.CfgCdrField{
|
||||
Tag: "LastUsed",
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("~Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets:s/^(.*)$/test/(test);Multiple-Services-Credit-Control>Rating-Group(1)", utils.INFIELD_SEP),
|
||||
FieldId: "LastUsed",
|
||||
Type: "*handler",
|
||||
HandlerId: "*sum",
|
||||
Value: utils.ParseRSRFieldsMustCompile("Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets;^|;Multiple-Services-Credit-Control>Used-Service-Unit>CC-Output-Octets", utils.INFIELD_SEP),
|
||||
Mandatory: true,
|
||||
},
|
||||
}
|
||||
eSMGEv = sessionmanager.SMGenericEvent{"EventName": "DIAMETER_CCR", "LastUsed": "54239"}
|
||||
if rSMGEv, err := ccr.AsSMGenericEvent(cfgFlds); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eSMGEv, rSMGEv) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSMGEv, rSMGEv)
|
||||
}
|
||||
cfgFlds = []*config.CfgCdrField{
|
||||
&config.CfgCdrField{
|
||||
Tag: "LastUsed",
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("~Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets:s/^(.*)$/test/(test);Multiple-Services-Credit-Control>Rating-Group(99)", utils.INFIELD_SEP),
|
||||
FieldId: "LastUsed",
|
||||
Type: "*handler",
|
||||
HandlerId: "*sum",
|
||||
Value: utils.ParseRSRFieldsMustCompile("Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets;^|;Multiple-Services-Credit-Control>Used-Service-Unit>CC-Output-Octets", utils.INFIELD_SEP),
|
||||
Mandatory: true,
|
||||
},
|
||||
}
|
||||
eSMGEv = sessionmanager.SMGenericEvent{"EventName": "DIAMETER_CCR", "LastUsed": "4420"}
|
||||
if rSMGEv, err := ccr.AsSMGenericEvent(cfgFlds); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eSMGEv, rSMGEv) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSMGEv, rSMGEv)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPassesFieldFilter(t *testing.T) {
|
||||
m := diam.NewRequest(diam.CreditControl, 4, nil) // Multiple-Services-Credit-Control>Rating-Group
|
||||
if pass, _ := passesFieldFilter(m, utils.ParseRSRFieldsMustCompile("Multiple-Services-Credit-Control>Rating-Group(^$)", utils.INFIELD_SEP)[0], nil); !pass {
|
||||
t.Error("Does not pass")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ func (self *ApierV1) GetAccounts(attr utils.AttrGetAccounts, reply *[]interface{
|
||||
var accountKeys []string
|
||||
var err error
|
||||
if len(attr.AccountIds) == 0 {
|
||||
if accountKeys, err = self.AccountDb.GetKeysForPrefix(utils.ACCOUNT_PREFIX + attr.Tenant); err != nil {
|
||||
if accountKeys, err = self.AccountDb.GetKeysForPrefix(utils.ACCOUNT_PREFIX+attr.Tenant, true); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
@@ -426,7 +426,7 @@ func (self *ApierV1) modifyBalance(aType string, attr *AttrAddBalance, reply *st
|
||||
Uuid: attr.BalanceUuid,
|
||||
ID: attr.BalanceId,
|
||||
Type: utils.StringPointer(attr.BalanceType),
|
||||
Value: utils.Float64Pointer(attr.Value),
|
||||
Value: &utils.ValueFormula{Static: attr.Value},
|
||||
ExpirationDate: expTime,
|
||||
RatingSubject: attr.RatingSubject,
|
||||
Weight: attr.Weight,
|
||||
@@ -514,7 +514,6 @@ func (self *ApierV1) SetBalance(attr *AttrSetBalance, reply *string) error {
|
||||
Uuid: attr.BalanceUUID,
|
||||
ID: attr.BalanceID,
|
||||
Type: utils.StringPointer(attr.BalanceType),
|
||||
Value: attr.Value,
|
||||
ExpirationDate: expTime,
|
||||
RatingSubject: attr.RatingSubject,
|
||||
Weight: attr.Weight,
|
||||
@@ -522,6 +521,9 @@ func (self *ApierV1) SetBalance(attr *AttrSetBalance, reply *string) error {
|
||||
Disabled: attr.Disabled,
|
||||
},
|
||||
}
|
||||
if attr.Value != nil {
|
||||
a.Balance.Value = &utils.ValueFormula{Static: *attr.Value}
|
||||
}
|
||||
if attr.Directions != nil {
|
||||
a.Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(*attr.Directions))
|
||||
}
|
||||
@@ -567,12 +569,11 @@ func (self *ApierV1) RemoveBalances(attr *AttrSetBalance, reply *string) error {
|
||||
at := &engine.ActionTiming{}
|
||||
at.SetAccountIDs(utils.StringMap{accID: true})
|
||||
a := &engine.Action{
|
||||
ActionType: engine.SET_BALANCE,
|
||||
ActionType: engine.REMOVE_BALANCE,
|
||||
Balance: &engine.BalanceFilter{
|
||||
Uuid: attr.BalanceUUID,
|
||||
ID: attr.BalanceID,
|
||||
Type: utils.StringPointer(attr.BalanceType),
|
||||
Value: attr.Value,
|
||||
ExpirationDate: expTime,
|
||||
RatingSubject: attr.RatingSubject,
|
||||
Weight: attr.Weight,
|
||||
@@ -580,6 +581,9 @@ func (self *ApierV1) RemoveBalances(attr *AttrSetBalance, reply *string) error {
|
||||
Disabled: attr.Disabled,
|
||||
},
|
||||
}
|
||||
if attr.Value != nil {
|
||||
a.Balance.Value = &utils.ValueFormula{Static: *attr.Value}
|
||||
}
|
||||
if attr.Directions != nil {
|
||||
a.Balance.Directions = utils.StringMapPointer(utils.ParseStringMap(*attr.Directions))
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
@@ -51,7 +52,7 @@ func (self *ApierV1) AddRatingSubjectAliases(attrs AttrAddRatingSubjectAliases,
|
||||
als := engine.Alias{Direction: utils.META_OUT, Tenant: attrs.Tenant, Category: attrs.Category, Account: alias, Subject: alias, Context: utils.ALIAS_CONTEXT_RATING,
|
||||
Values: engine.AliasValues{&engine.AliasValue{DestinationId: utils.META_ANY,
|
||||
Pairs: engine.AliasPairs{"Account": map[string]string{alias: attrs.Subject}, "Subject": map[string]string{alias: attrs.Subject}}, Weight: 10.0}}}
|
||||
if err := aliases.SetAlias(als, &ignr); err != nil {
|
||||
if err := aliases.Call("AliasesV1.SetAlias", &engine.AttrAddAlias{Alias: &als}, &ignr); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
}
|
||||
@@ -69,7 +70,7 @@ func (self *ApierV1) RemRatingSubjectAliases(tenantRatingSubject engine.TenantRa
|
||||
return errors.New("ALIASES_NOT_ENABLED")
|
||||
}
|
||||
var reverseAliases map[string][]*engine.Alias
|
||||
if err := aliases.GetReverseAlias(engine.AttrReverseAlias{Target: "Subject", Alias: tenantRatingSubject.Subject, Context: utils.ALIAS_CONTEXT_RATING}, &reverseAliases); err != nil {
|
||||
if err := aliases.Call("AliasesV1.GetReverseAlias", &engine.AttrReverseAlias{Target: "Subject", Alias: tenantRatingSubject.Subject, Context: utils.ALIAS_CONTEXT_RATING}, &reverseAliases); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
var ignr string
|
||||
@@ -78,7 +79,7 @@ func (self *ApierV1) RemRatingSubjectAliases(tenantRatingSubject engine.TenantRa
|
||||
if alias.Tenant != tenantRatingSubject.Tenant {
|
||||
continue // From another tenant
|
||||
}
|
||||
if err := aliases.RemoveAlias(*alias, &ignr); err != nil {
|
||||
if err := aliases.Call("AliasesV1.RemoveAlias", alias, &ignr); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
}
|
||||
@@ -103,7 +104,7 @@ func (self *ApierV1) AddAccountAliases(attrs AttrAddAccountAliases, reply *strin
|
||||
als := engine.Alias{Direction: utils.META_OUT, Tenant: attrs.Tenant, Category: attrs.Category, Account: alias, Subject: alias, Context: utils.ALIAS_CONTEXT_RATING,
|
||||
Values: engine.AliasValues{&engine.AliasValue{DestinationId: utils.META_ANY,
|
||||
Pairs: engine.AliasPairs{"Account": map[string]string{alias: attrs.Account}, "Subject": map[string]string{alias: attrs.Account}}, Weight: 10.0}}}
|
||||
if err := aliases.SetAlias(als, &ignr); err != nil {
|
||||
if err := aliases.Call("AliasesV1.SetAlias", &engine.AttrAddAlias{Alias: &als}, &ignr); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
}
|
||||
@@ -121,7 +122,7 @@ func (self *ApierV1) RemAccountAliases(tenantAccount engine.TenantAccount, reply
|
||||
return errors.New("ALIASES_NOT_ENABLED")
|
||||
}
|
||||
var reverseAliases map[string][]*engine.Alias
|
||||
if err := aliases.GetReverseAlias(engine.AttrReverseAlias{Target: "Account", Alias: tenantAccount.Account, Context: utils.ALIAS_CONTEXT_RATING}, &reverseAliases); err != nil {
|
||||
if err := aliases.Call("AliasesV1.GetReverseAlias", &engine.AttrReverseAlias{Target: "Account", Alias: tenantAccount.Account, Context: utils.ALIAS_CONTEXT_RATING}, &reverseAliases); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
var ignr string
|
||||
@@ -130,7 +131,7 @@ func (self *ApierV1) RemAccountAliases(tenantAccount engine.TenantAccount, reply
|
||||
if alias.Tenant != tenantAccount.Tenant {
|
||||
continue // From another tenant
|
||||
}
|
||||
if err := aliases.RemoveAlias(*alias, &ignr); err != nil {
|
||||
if err := aliases.Call("AliasesV1.RemoveAlias", alias, &ignr); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/scheduler"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/rpcclient"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -48,8 +49,9 @@ type ApierV1 struct {
|
||||
Sched *scheduler.Scheduler
|
||||
Config *config.CGRConfig
|
||||
Responder *engine.Responder
|
||||
CdrStatsSrv engine.StatsInterface
|
||||
Users engine.UserService
|
||||
CdrStatsSrv rpcclient.RpcClientConnection
|
||||
Users rpcclient.RpcClientConnection
|
||||
CDRs rpcclient.RpcClientConnection // FixMe: populate it from cgr-engine
|
||||
}
|
||||
|
||||
func (self *ApierV1) GetDestination(dstId string, reply *engine.Destination) error {
|
||||
@@ -103,11 +105,12 @@ func (self *ApierV1) GetRatingPlan(rplnId string, reply *engine.RatingPlan) erro
|
||||
}
|
||||
|
||||
func (self *ApierV1) ExecuteAction(attr *utils.AttrExecuteAction, reply *string) error {
|
||||
accID := utils.AccountKey(attr.Tenant, attr.Account)
|
||||
at := &engine.ActionTiming{
|
||||
ActionsID: attr.ActionsId,
|
||||
}
|
||||
at.SetAccountIDs(utils.StringMap{accID: true})
|
||||
if attr.Tenant != "" && attr.Account != "" {
|
||||
at.SetAccountIDs(utils.StringMap{utils.AccountKey(attr.Tenant, attr.Account): true})
|
||||
}
|
||||
if err := at.Execute(); err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
@@ -375,13 +378,13 @@ func (self *ApierV1) LoadTariffPlanFromStorDb(attrs AttrLoadTpFromStorDb, reply
|
||||
}
|
||||
|
||||
if len(cstKeys) != 0 && self.CdrStatsSrv != nil {
|
||||
if err := self.CdrStatsSrv.ReloadQueues(cstKeys, nil); err != nil {
|
||||
if err := self.CdrStatsSrv.Call("CDRStatsV1.ReloadQueues", cstKeys, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(userKeys) != 0 && self.Users != nil {
|
||||
var r string
|
||||
if err := self.Users.ReloadUsers("", &r); err != nil {
|
||||
if err := self.Users.Call("AliasV1.ReloadUsers", "", &r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -502,10 +505,10 @@ func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error
|
||||
}
|
||||
storeActions := make(engine.Actions, len(attrs.Actions))
|
||||
for idx, apiAct := range attrs.Actions {
|
||||
var units *float64
|
||||
var vf *utils.ValueFormula
|
||||
if apiAct.Units != "" {
|
||||
if x, err := strconv.ParseFloat(apiAct.Units, 64); err == nil {
|
||||
units = &x
|
||||
if x, err := utils.ParseBalanceFilterValue(apiAct.Units); err == nil {
|
||||
vf = x
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
@@ -521,17 +524,17 @@ func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error
|
||||
}
|
||||
|
||||
a := &engine.Action{
|
||||
Id: utils.GenUUID(),
|
||||
Id: attrs.ActionsId,
|
||||
ActionType: apiAct.Identifier,
|
||||
Weight: apiAct.Weight,
|
||||
ExpirationString: apiAct.ExpiryTime,
|
||||
ExtraParameters: apiAct.ExtraParameters,
|
||||
Filter: apiAct.Filter,
|
||||
Balance: &engine.BalanceFilter{ // TODO: update this part
|
||||
Uuid: utils.StringPointer(utils.GenUUID()),
|
||||
Uuid: utils.StringPointer(apiAct.BalanceUuid),
|
||||
ID: utils.StringPointer(apiAct.BalanceId),
|
||||
Type: utils.StringPointer(apiAct.BalanceType),
|
||||
Value: units,
|
||||
Value: vf,
|
||||
Weight: weight,
|
||||
Directions: utils.StringMapPointer(utils.ParseStringMap(apiAct.Directions)),
|
||||
DestinationIDs: utils.StringMapPointer(utils.ParseStringMap(apiAct.DestinationIds)),
|
||||
@@ -560,7 +563,8 @@ func (self *ApierV1) GetActions(actsId string, reply *[]*utils.TPAction) error {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
for _, engAct := range engActs {
|
||||
act := &utils.TPAction{Identifier: engAct.ActionType,
|
||||
act := &utils.TPAction{
|
||||
Identifier: engAct.ActionType,
|
||||
ExpiryTime: engAct.ExpirationString,
|
||||
ExtraParameters: engAct.ExtraParameters,
|
||||
Filter: engAct.Filter,
|
||||
@@ -808,23 +812,23 @@ func (self *ApierV1) GetCacheStats(attrs utils.AttrCacheStats, reply *utils.Cach
|
||||
cs.DerivedChargers = cache2go.CountEntries(utils.DERIVEDCHARGERS_PREFIX)
|
||||
cs.LcrProfiles = cache2go.CountEntries(utils.LCR_PREFIX)
|
||||
cs.Aliases = cache2go.CountEntries(utils.ALIASES_PREFIX)
|
||||
if self.CdrStatsSrv != nil && self.Config.CDRStatsEnabled {
|
||||
if self.CdrStatsSrv != nil {
|
||||
var queueIds []string
|
||||
if err := self.CdrStatsSrv.GetQueueIds(0, &queueIds); err != nil {
|
||||
if err := self.CdrStatsSrv.Call("CDRStatsV1.GetQueueIds", 0, &queueIds); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
cs.CdrStats = len(queueIds)
|
||||
}
|
||||
if self.Config.RaterUserServer == utils.INTERNAL {
|
||||
if self.Users != nil {
|
||||
var ups engine.UserProfiles
|
||||
if err := self.Users.GetUsers(engine.UserProfile{}, &ups); err != nil {
|
||||
if err := self.Users.Call("UsersV1.GetUsers", &engine.UserProfile{}, &ups); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
cs.Users = len(ups)
|
||||
}
|
||||
if loadHistInsts, err := self.AccountDb.GetLoadHistory(1, false); err != nil || len(loadHistInsts) == 0 {
|
||||
if err != nil { // Not really an error here since we only count in cache
|
||||
utils.Logger.Err(fmt.Sprintf("ApierV1.GetCacheStats, error on GetLoadHistory: %s", err.Error()))
|
||||
utils.Logger.Warning(fmt.Sprintf("ApierV1.GetCacheStats, error on GetLoadHistory: %s", err.Error()))
|
||||
}
|
||||
cs.LastLoadId = utils.NOT_AVAILABLE
|
||||
cs.LastLoadTime = utils.NOT_AVAILABLE
|
||||
@@ -960,13 +964,14 @@ func (self *ApierV1) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder,
|
||||
self.Sched.Reload(true)
|
||||
}
|
||||
if len(cstKeys) != 0 && self.CdrStatsSrv != nil {
|
||||
if err := self.CdrStatsSrv.ReloadQueues(cstKeys, nil); err != nil {
|
||||
var out int
|
||||
if err := self.CdrStatsSrv.Call("CDRStatsV1.ReloadQueues", cstKeys, &out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(userKeys) != 0 && self.Users != nil {
|
||||
var r string
|
||||
if err := self.Users.ReloadUsers("", &r); err != nil {
|
||||
if err := self.Users.Call("UsersV1.ReloadUsers", "", &r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1060,3 +1065,66 @@ func (self *ApierV1) GetLoadHistory(attrs utils.Paginator, reply *[]*engine.Load
|
||||
*reply = loadHist[offset:nrItems]
|
||||
return nil
|
||||
}
|
||||
|
||||
type AttrRemActions struct {
|
||||
ActionIDs []string
|
||||
}
|
||||
|
||||
func (self *ApierV1) RemActions(attr AttrRemActions, reply *string) error {
|
||||
if attr.ActionIDs == nil {
|
||||
err := utils.ErrNotFound
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
// The check could lead to very long execution time. So we decided to leave it at the user's risck.'
|
||||
/*
|
||||
stringMap := utils.NewStringMap(attr.ActionIDs...)
|
||||
keys, err := self.RatingDb.GetKeysForPrefix(utils.ACTION_TRIGGER_PREFIX, true)
|
||||
if err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
for _, key := range keys {
|
||||
getAttrs, err := self.RatingDb.GetActionTriggers(key[len(utils.ACTION_TRIGGER_PREFIX):])
|
||||
if err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
for _, atr := range getAttrs {
|
||||
if _, found := stringMap[atr.ActionsID]; found {
|
||||
// found action trigger referencing action; abort
|
||||
err := fmt.Errorf("action %s refenced by action trigger %s", atr.ActionsID, atr.ID)
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
allAplsMap, err := self.RatingDb.GetAllActionPlans()
|
||||
if err != nil && err != utils.ErrNotFound {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
for _, apl := range allAplsMap {
|
||||
for _, atm := range apl.ActionTimings {
|
||||
if _, found := stringMap[atm.ActionsID]; found {
|
||||
err := fmt.Errorf("action %s refenced by action plan %s", atm.ActionsID, apl.Id)
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
for _, aID := range attr.ActionIDs {
|
||||
if err := self.RatingDb.RemoveActions(aID); err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := self.RatingDb.CacheRatingPrefixes(utils.ACTION_PREFIX); err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
*reply = utils.OK
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1274,7 +1274,7 @@ func TestApierLoadTariffPlanFromFolder(t *testing.T) {
|
||||
} else if reply != "OK" {
|
||||
t.Error("Calling ApierV1.LoadTariffPlanFromFolder got reply: ", reply)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
time.Sleep(time.Duration(2**waitRater) * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestApierResetDataAfterLoadFromFolder(t *testing.T) {
|
||||
@@ -1294,11 +1294,11 @@ func TestApierResetDataAfterLoadFromFolder(t *testing.T) {
|
||||
if err := rater.Call("ApierV1.GetCacheStats", args, &rcvStats); err != nil {
|
||||
t.Error("Got error on ApierV1.GetCacheStats: ", err.Error())
|
||||
} else {
|
||||
if rcvStats.Destinations != 4 ||
|
||||
rcvStats.RatingPlans != 3 ||
|
||||
rcvStats.RatingProfiles != 3 ||
|
||||
rcvStats.Actions != 6 ||
|
||||
rcvStats.DerivedChargers != 2 {
|
||||
if rcvStats.Destinations != 5 ||
|
||||
rcvStats.RatingPlans != 5 ||
|
||||
rcvStats.RatingProfiles != 5 ||
|
||||
rcvStats.Actions != 11 ||
|
||||
rcvStats.DerivedChargers != 3 {
|
||||
t.Errorf("Calling ApierV1.GetCacheStats received: %+v", rcvStats)
|
||||
}
|
||||
}
|
||||
@@ -1359,7 +1359,7 @@ func TestApierGetCallCostLog(t *testing.T) {
|
||||
}
|
||||
attrs.CgrId = "dummyid"
|
||||
attrs.RunId = "default"
|
||||
if err := rater.Call("ApierV1.GetCallCostLog", attrs, &cc); err == nil || err.Error() != "SERVER_ERROR: record not found" {
|
||||
if err := rater.Call("ApierV1.GetCallCostLog", attrs, &cc); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error("ApierV1.GetCallCostLog: should return NOT_FOUND, got:", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
@@ -26,19 +27,19 @@ import (
|
||||
)
|
||||
|
||||
// Retrieves the callCost out of CGR logDb
|
||||
func (apier *ApierV1) GetCallCostLog(attrs utils.AttrGetCallCost, reply *engine.CallCost) error {
|
||||
func (apier *ApierV1) GetCallCostLog(attrs utils.AttrGetCallCost, reply *engine.SMCost) error {
|
||||
if attrs.CgrId == "" {
|
||||
return utils.NewErrMandatoryIeMissing("CgrId")
|
||||
}
|
||||
if attrs.RunId == "" {
|
||||
attrs.RunId = utils.META_DEFAULT
|
||||
}
|
||||
if cc, err := apier.CdrDb.GetCallCostLog(attrs.CgrId, attrs.RunId); err != nil {
|
||||
if smcs, err := apier.CdrDb.GetSMCosts(attrs.CgrId, attrs.RunId, "", ""); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
} else if cc == nil {
|
||||
} else if len(smcs) == 0 {
|
||||
return utils.ErrNotFound
|
||||
} else {
|
||||
*reply = *cc
|
||||
*reply = *smcs[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -85,3 +86,11 @@ func (apier *ApierV1) RemoveCDRs(attrs utils.RPCCDRsFilter, reply *string) error
|
||||
*reply = "OK"
|
||||
return nil
|
||||
}
|
||||
|
||||
// New way of (re-)rating CDRs
|
||||
func (apier *ApierV1) RateCDRs(attrs utils.AttrRateCDRs, reply *string) error {
|
||||
if apier.CDRs == nil {
|
||||
return errors.New("CDRS_NOT_ENABLED")
|
||||
}
|
||||
return apier.CDRs.Call("CDRsV1.RateCDRs", attrs, reply)
|
||||
}
|
||||
|
||||
@@ -23,11 +23,12 @@ import (
|
||||
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/rpcclient"
|
||||
)
|
||||
|
||||
// Interact with Stats server
|
||||
type CDRStatsV1 struct {
|
||||
CdrStats engine.StatsInterface
|
||||
CdrStats rpcclient.RpcClientConnection
|
||||
}
|
||||
|
||||
type AttrGetMetrics struct {
|
||||
@@ -38,31 +39,32 @@ func (sts *CDRStatsV1) GetMetrics(attr AttrGetMetrics, reply *map[string]float64
|
||||
if len(attr.StatsQueueId) == 0 {
|
||||
return fmt.Errorf("%s:StatsQueueId", utils.ErrMandatoryIeMissing.Error())
|
||||
}
|
||||
return sts.CdrStats.GetValues(attr.StatsQueueId, reply)
|
||||
return sts.CdrStats.Call("CDRStatsV1.GetValues", attr.StatsQueueId, reply)
|
||||
}
|
||||
|
||||
func (sts *CDRStatsV1) GetQueueIds(empty string, reply *[]string) error {
|
||||
return sts.CdrStats.GetQueueIds(0, reply)
|
||||
return sts.CdrStats.Call("CDRStatsV1.GetQueueIds", 0, reply)
|
||||
}
|
||||
|
||||
func (sts *CDRStatsV1) GetQueue(id string, sq *engine.StatsQueue) error {
|
||||
return sts.CdrStats.GetQueue(id, sq)
|
||||
return sts.CdrStats.Call("CDRStatsV1.GetQueue", id, sq)
|
||||
}
|
||||
|
||||
func (sts *CDRStatsV1) AddQueue(cs *engine.CdrStats, reply *int) error {
|
||||
return sts.CdrStats.AddQueue(cs, reply)
|
||||
return sts.CdrStats.Call("CDRStatsV1.AddQueue", cs, reply)
|
||||
}
|
||||
|
||||
func (sts *CDRStatsV1) RemoveQueue(qID string, reply *int) error {
|
||||
return sts.CdrStats.RemoveQueue(qID, reply)
|
||||
return sts.CdrStats.Call("CDRStatsV1.RemoveQueue", qID, reply)
|
||||
}
|
||||
|
||||
func (sts *CDRStatsV1) GetQueueTriggers(id string, ats *engine.ActionTriggers) error {
|
||||
return sts.CdrStats.GetQueueTriggers(id, ats)
|
||||
return sts.CdrStats.Call("CDRStatsV1.GetQueueTriggers", id, ats)
|
||||
}
|
||||
|
||||
func (sts *CDRStatsV1) ReloadQueues(attr utils.AttrCDRStatsReloadQueues, reply *string) error {
|
||||
if err := sts.CdrStats.ReloadQueues(attr.StatsQueueIds, nil); err != nil {
|
||||
var out int
|
||||
if err := sts.CdrStats.Call("CDRStatsV1.ReloadQueues", attr.StatsQueueIds, &out); err != nil {
|
||||
return err
|
||||
}
|
||||
*reply = utils.OK
|
||||
@@ -70,7 +72,8 @@ func (sts *CDRStatsV1) ReloadQueues(attr utils.AttrCDRStatsReloadQueues, reply *
|
||||
}
|
||||
|
||||
func (sts *CDRStatsV1) ResetQueues(attr utils.AttrCDRStatsReloadQueues, reply *string) error {
|
||||
if err := sts.CdrStats.ResetQueues(attr.StatsQueueIds, nil); err != nil {
|
||||
var out int
|
||||
if err := sts.CdrStats.Call("CDRStatsV1.ResetQueues", attr.StatsQueueIds, &out); err != nil {
|
||||
return err
|
||||
}
|
||||
*reply = utils.OK
|
||||
|
||||
@@ -104,6 +104,13 @@ func TestCDRStatsLclGetQueueIds2(t *testing.T) {
|
||||
} else if len(eQueueIds) != len(queueIds) {
|
||||
t.Errorf("Expecting: %v, received: %v", eQueueIds, queueIds)
|
||||
}
|
||||
var rcvMetrics map[string]float64
|
||||
expectedMetrics := map[string]float64{"ASR": -1, "ACD": -1}
|
||||
if err := cdrstRpc.Call("CDRStatsV1.GetMetrics", AttrGetMetrics{StatsQueueId: "CDRST4"}, &rcvMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(expectedMetrics, rcvMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", expectedMetrics, rcvMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDRStatsLclPostCdrs(t *testing.T) {
|
||||
@@ -112,28 +119,28 @@ func TestCDRStatsLclPostCdrs(t *testing.T) {
|
||||
}
|
||||
httpClient := new(http.Client)
|
||||
storedCdrs := []*engine.CDR{
|
||||
&engine.CDR{CGRID: utils.Sha1("dsafdsafa", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf",
|
||||
&engine.CDR{CGRID: utils.Sha1("dsafdsafa", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafa",
|
||||
OriginHost: "192.168.1.1", Source: "test",
|
||||
RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(),
|
||||
AnswerTime: time.Now(), RunID: utils.DEFAULT_RUNID, Usage: time.Duration(10) * time.Second,
|
||||
ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
},
|
||||
&engine.CDR{CGRID: utils.Sha1("dsafdsafb", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf",
|
||||
&engine.CDR{CGRID: utils.Sha1("dsafdsafb", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafb",
|
||||
OriginHost: "192.168.1.1", Source: "test",
|
||||
RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(),
|
||||
AnswerTime: time.Now(), RunID: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(5) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
},
|
||||
&engine.CDR{CGRID: utils.Sha1("dsafdsafc", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf",
|
||||
&engine.CDR{CGRID: utils.Sha1("dsafdsafc", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafc",
|
||||
OriginHost: "192.168.1.1", Source: "test",
|
||||
RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Now(),
|
||||
RunID: utils.DEFAULT_RUNID,
|
||||
Usage: time.Duration(30) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, Cost: 1.01,
|
||||
},
|
||||
&engine.CDR{CGRID: utils.Sha1("dsafdsafd", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsaf",
|
||||
&engine.CDR{CGRID: utils.Sha1("dsafdsafd", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), OrderID: 123, ToR: utils.VOICE, OriginID: "dsafdsafd",
|
||||
OriginHost: "192.168.1.1", Source: "test",
|
||||
RequestType: utils.META_RATED, Direction: "*out", Tenant: "cgrates.org",
|
||||
Category: "call", Account: "1001", Subject: "1001", Destination: "+4986517174963", SetupTime: time.Now(), AnswerTime: time.Time{},
|
||||
@@ -147,7 +154,6 @@ func TestCDRStatsLclPostCdrs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
|
||||
}
|
||||
|
||||
func TestCDRStatsLclGetMetrics1(t *testing.T) {
|
||||
@@ -205,3 +211,12 @@ func TestCDRStatsLclResetMetrics(t *testing.T) {
|
||||
t.Errorf("Expecting: %v, received: %v", expectedMetrics2, rcvMetrics2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCDRStatsLclKillEngine(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
if err := engine.KillEngine(*waitRater); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ type CdrsV1 struct {
|
||||
|
||||
// Designed for CGR internal usage
|
||||
func (self *CdrsV1) ProcessCdr(cdr *engine.CDR, reply *string) error {
|
||||
if err := self.CdrSrv.ProcessCdr(cdr); err != nil {
|
||||
if err := self.CdrSrv.LocalProcessCdr(cdr); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
*reply = utils.OK
|
||||
@@ -46,7 +46,7 @@ func (self *CdrsV1) ProcessExternalCdr(cdr *engine.ExternalCDR, reply *string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remotely start mediation with specific runid, runs asynchronously, it's status will be displayed in syslog
|
||||
// Remotely (re)rating, deprecated
|
||||
func (self *CdrsV1) RateCdrs(attrs utils.AttrRateCdrs, reply *string) error {
|
||||
cdrsFltr, err := attrs.AsCDRsFilter(self.CdrSrv.Timezone())
|
||||
if err != nil {
|
||||
@@ -59,10 +59,6 @@ func (self *CdrsV1) RateCdrs(attrs utils.AttrRateCdrs, reply *string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CdrsV1) LogCallCost(ccl *engine.CallCostLog, reply *string) error {
|
||||
if err := self.CdrSrv.LogCallCost(ccl); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
*reply = utils.OK
|
||||
return nil
|
||||
func (self *CdrsV1) StoreSMCost(attr engine.AttrCDRSStoreSMCost, reply *string) error {
|
||||
return self.CdrSrv.V1StoreSMCost(attr, reply)
|
||||
}
|
||||
|
||||
@@ -97,6 +97,9 @@ func (self *SMGenericV1) ActiveSessions(attrs utils.AttrSMGGetActiveSessions, re
|
||||
if attrs.ToR != nil && *attrs.ToR != as.TOR {
|
||||
continue
|
||||
}
|
||||
if attrs.OriginID != nil && *attrs.OriginID != as.OriginID {
|
||||
continue
|
||||
}
|
||||
if attrs.RunID != nil && *attrs.RunID != as.RunId {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ func TestSMGV1CacheStats(t *testing.T) {
|
||||
}
|
||||
var rcvStats *utils.CacheStats
|
||||
|
||||
expectedStats := &utils.CacheStats{Destinations: 4, RatingPlans: 4, RatingProfiles: 9, Actions: 7, ActionPlans: 4, SharedGroups: 1, Aliases: 1,
|
||||
expectedStats := &utils.CacheStats{Destinations: 4, RatingPlans: 4, RatingProfiles: 9, Actions: 8, ActionPlans: 4, SharedGroups: 1, Aliases: 1,
|
||||
DerivedChargers: 1, LcrProfiles: 5, CdrStats: 6, Users: 3, LastLoadId: smgV1LoadInst.LoadId, LastLoadTime: smgV1LoadInst.LoadTime.Format(time.RFC3339)}
|
||||
var args utils.AttrCacheStats
|
||||
if err := smgV1Rpc.Call("ApierV2.GetCacheStats", args, &rcvStats); err != nil {
|
||||
|
||||
@@ -129,7 +129,15 @@ func (self *ApierV1) RemoveAccountActionTriggers(attr AttrRemoveAccountActionTri
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ApierV1) ResetAccountActionTriggers(attr AttrRemoveAccountActionTriggers, reply *string) error {
|
||||
type AttrResetAccountActionTriggers struct {
|
||||
Tenant string
|
||||
Account string
|
||||
GroupID string
|
||||
UniqueID string
|
||||
Executed bool
|
||||
}
|
||||
|
||||
func (self *ApierV1) ResetAccountActionTriggers(attr AttrResetAccountActionTriggers, reply *string) error {
|
||||
|
||||
if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 {
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
@@ -146,11 +154,13 @@ func (self *ApierV1) ResetAccountActionTriggers(attr AttrRemoveAccountActionTrig
|
||||
if (attr.UniqueID == "" || at.UniqueID == attr.UniqueID) &&
|
||||
(attr.GroupID == "" || at.ID == attr.GroupID) {
|
||||
// reset action trigger
|
||||
at.Executed = false
|
||||
at.Executed = attr.Executed
|
||||
}
|
||||
|
||||
}
|
||||
account.ExecuteActionTriggers(nil)
|
||||
if attr.Executed == false {
|
||||
account.ExecuteActionTriggers(nil)
|
||||
}
|
||||
if err := self.AccountDb.SetAccount(account); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -175,7 +185,7 @@ type AttrSetAccountActionTriggers struct {
|
||||
MinSleep *string
|
||||
ExpirationDate *string
|
||||
ActivationDate *string
|
||||
BalanceId *string
|
||||
BalanceID *string
|
||||
BalanceType *string
|
||||
BalanceDirections *[]string
|
||||
BalanceDestinationIds *[]string
|
||||
@@ -188,7 +198,7 @@ type AttrSetAccountActionTriggers struct {
|
||||
BalanceBlocker *bool
|
||||
BalanceDisabled *bool
|
||||
MinQueuedItems *int
|
||||
ActionsId *string
|
||||
ActionsID *string
|
||||
}
|
||||
|
||||
func (self *ApierV1) SetAccountActionTriggers(attr AttrSetAccountActionTriggers, reply *string) error {
|
||||
@@ -238,8 +248,9 @@ func (self *ApierV1) SetAccountActionTriggers(attr AttrSetAccountActionTriggers,
|
||||
}
|
||||
at.ActivationDate = actTime
|
||||
}
|
||||
if attr.BalanceId != nil {
|
||||
at.Balance.ID = attr.BalanceId
|
||||
at.Balance = &engine.BalanceFilter{}
|
||||
if attr.BalanceID != nil {
|
||||
at.Balance.ID = attr.BalanceID
|
||||
}
|
||||
if attr.BalanceType != nil {
|
||||
at.Balance.Type = attr.BalanceType
|
||||
@@ -281,8 +292,8 @@ func (self *ApierV1) SetAccountActionTriggers(attr AttrSetAccountActionTriggers,
|
||||
if attr.MinQueuedItems != nil {
|
||||
at.MinQueuedItems = *attr.MinQueuedItems
|
||||
}
|
||||
if attr.ActionsId != nil {
|
||||
at.ActionsID = *attr.ActionsId
|
||||
if attr.ActionsID != nil {
|
||||
at.ActionsID = *attr.ActionsID
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,3 +311,180 @@ func (self *ApierV1) SetAccountActionTriggers(attr AttrSetAccountActionTriggers,
|
||||
*reply = utils.OK
|
||||
return nil
|
||||
}
|
||||
|
||||
type AttrSetActionTrigger struct {
|
||||
GroupID string
|
||||
UniqueID string
|
||||
ThresholdType *string
|
||||
ThresholdValue *float64
|
||||
Recurrent *bool
|
||||
MinSleep *string
|
||||
ExpirationDate *string
|
||||
ActivationDate *string
|
||||
BalanceID *string
|
||||
BalanceType *string
|
||||
BalanceDirections *[]string
|
||||
BalanceDestinationIds *[]string
|
||||
BalanceWeight *float64
|
||||
BalanceExpirationDate *string
|
||||
BalanceTimingTags *[]string
|
||||
BalanceRatingSubject *string
|
||||
BalanceCategories *[]string
|
||||
BalanceSharedGroups *[]string
|
||||
BalanceBlocker *bool
|
||||
BalanceDisabled *bool
|
||||
MinQueuedItems *int
|
||||
ActionsID *string
|
||||
}
|
||||
|
||||
func (self *ApierV1) SetActionTrigger(attr AttrSetActionTrigger, reply *string) error {
|
||||
|
||||
if missing := utils.MissingStructFields(&attr, []string{"GroupID"}); len(missing) != 0 {
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
|
||||
atrs, _ := self.RatingDb.GetActionTriggers(attr.GroupID)
|
||||
var newAtr *engine.ActionTrigger
|
||||
if attr.UniqueID != "" {
|
||||
//search for exiting one
|
||||
for _, atr := range atrs {
|
||||
if atr.UniqueID == attr.UniqueID {
|
||||
newAtr = atr
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if newAtr == nil {
|
||||
newAtr = &engine.ActionTrigger{}
|
||||
atrs = append(atrs, newAtr)
|
||||
}
|
||||
newAtr.ID = attr.GroupID
|
||||
if attr.UniqueID != "" {
|
||||
newAtr.UniqueID = attr.UniqueID
|
||||
} else {
|
||||
newAtr.UniqueID = utils.GenUUID()
|
||||
}
|
||||
|
||||
if attr.ThresholdType != nil {
|
||||
newAtr.ThresholdType = *attr.ThresholdType
|
||||
}
|
||||
if attr.ThresholdValue != nil {
|
||||
newAtr.ThresholdValue = *attr.ThresholdValue
|
||||
}
|
||||
if attr.Recurrent != nil {
|
||||
newAtr.Recurrent = *attr.Recurrent
|
||||
}
|
||||
if attr.MinSleep != nil {
|
||||
minSleep, err := utils.ParseDurationWithSecs(*attr.MinSleep)
|
||||
if err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
newAtr.MinSleep = minSleep
|
||||
}
|
||||
if attr.ExpirationDate != nil {
|
||||
expTime, err := utils.ParseTimeDetectLayout(*attr.ExpirationDate, self.Config.DefaultTimezone)
|
||||
if err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
newAtr.ExpirationDate = expTime
|
||||
}
|
||||
if attr.ActivationDate != nil {
|
||||
actTime, err := utils.ParseTimeDetectLayout(*attr.ActivationDate, self.Config.DefaultTimezone)
|
||||
if err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
newAtr.ActivationDate = actTime
|
||||
}
|
||||
newAtr.Balance = &engine.BalanceFilter{}
|
||||
if attr.BalanceID != nil {
|
||||
newAtr.Balance.ID = attr.BalanceID
|
||||
}
|
||||
if attr.BalanceType != nil {
|
||||
newAtr.Balance.Type = attr.BalanceType
|
||||
}
|
||||
if attr.BalanceDirections != nil {
|
||||
newAtr.Balance.Directions = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDirections...))
|
||||
}
|
||||
if attr.BalanceDestinationIds != nil {
|
||||
newAtr.Balance.DestinationIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDestinationIds...))
|
||||
}
|
||||
if attr.BalanceWeight != nil {
|
||||
newAtr.Balance.Weight = attr.BalanceWeight
|
||||
}
|
||||
if attr.BalanceExpirationDate != nil {
|
||||
balanceExpTime, err := utils.ParseDate(*attr.BalanceExpirationDate)
|
||||
if err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
newAtr.Balance.ExpirationDate = &balanceExpTime
|
||||
}
|
||||
if attr.BalanceTimingTags != nil {
|
||||
newAtr.Balance.TimingIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceTimingTags...))
|
||||
}
|
||||
if attr.BalanceRatingSubject != nil {
|
||||
newAtr.Balance.RatingSubject = attr.BalanceRatingSubject
|
||||
}
|
||||
if attr.BalanceCategories != nil {
|
||||
newAtr.Balance.Categories = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceCategories...))
|
||||
}
|
||||
if attr.BalanceSharedGroups != nil {
|
||||
newAtr.Balance.SharedGroups = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceSharedGroups...))
|
||||
}
|
||||
if attr.BalanceBlocker != nil {
|
||||
newAtr.Balance.Blocker = attr.BalanceBlocker
|
||||
}
|
||||
if attr.BalanceDisabled != nil {
|
||||
newAtr.Balance.Disabled = attr.BalanceDisabled
|
||||
}
|
||||
if attr.MinQueuedItems != nil {
|
||||
newAtr.MinQueuedItems = *attr.MinQueuedItems
|
||||
}
|
||||
if attr.ActionsID != nil {
|
||||
newAtr.ActionsID = *attr.ActionsID
|
||||
}
|
||||
|
||||
if err := self.RatingDb.SetActionTriggers(attr.GroupID, atrs); err != nil {
|
||||
*reply = err.Error()
|
||||
return err
|
||||
}
|
||||
//no cache for action triggers
|
||||
*reply = utils.OK
|
||||
return nil
|
||||
}
|
||||
|
||||
type AttrGetActionTriggers struct {
|
||||
GroupIDs []string
|
||||
}
|
||||
|
||||
func (self *ApierV1) GetActionTriggers(attr AttrGetActionTriggers, atrs *engine.ActionTriggers) error {
|
||||
var allAttrs engine.ActionTriggers
|
||||
if len(attr.GroupIDs) > 0 {
|
||||
for _, key := range attr.GroupIDs {
|
||||
getAttrs, err := self.RatingDb.GetActionTriggers(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allAttrs = append(allAttrs, getAttrs...)
|
||||
}
|
||||
|
||||
} else {
|
||||
keys, err := self.RatingDb.GetKeysForPrefix(utils.ACTION_TRIGGER_PREFIX, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, key := range keys {
|
||||
getAttrs, err := self.RatingDb.GetActionTriggers(key[len(utils.ACTION_TRIGGER_PREFIX):])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allAttrs = append(allAttrs, getAttrs...)
|
||||
}
|
||||
}
|
||||
*atrs = allAttrs
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (self *ApierV2) GetAccounts(attr utils.AttrGetAccounts, reply *[]*engine.Ac
|
||||
var accountKeys []string
|
||||
var err error
|
||||
if len(attr.AccountIds) == 0 {
|
||||
if accountKeys, err = self.AccountDb.GetKeysForPrefix(utils.ACCOUNT_PREFIX + utils.ConcatenatedKey(attr.Tenant)); err != nil {
|
||||
if accountKeys, err = self.AccountDb.GetKeysForPrefix(utils.ACCOUNT_PREFIX+attr.Tenant, true); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -21,6 +21,7 @@ package v2
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
@@ -220,14 +221,12 @@ func (self *ApierV2) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder,
|
||||
dcsKeys[idx] = utils.DERIVEDCHARGERS_PREFIX + dc
|
||||
}
|
||||
aps, _ := loader.GetLoadedIds(utils.ACTION_PLAN_PREFIX)
|
||||
utils.Logger.Info("ApierV1.LoadTariffPlanFromFolder, reloading cache.")
|
||||
utils.Logger.Info("ApierV2.LoadTariffPlanFromFolder, reloading cache.")
|
||||
|
||||
cstKeys, _ := loader.GetLoadedIds(utils.CDR_STATS_PREFIX)
|
||||
userKeys, _ := loader.GetLoadedIds(utils.USERS_PREFIX)
|
||||
li := loader.GetLoadInstance()
|
||||
|
||||
// release the tp data
|
||||
loader.Init()
|
||||
loader.Init() // release the tp data
|
||||
|
||||
if err := self.RatingDb.CacheRatingPrefixValues(map[string][]string{
|
||||
utils.DESTINATION_PREFIX: dstKeys,
|
||||
@@ -247,21 +246,76 @@ func (self *ApierV2) LoadTariffPlanFromFolder(attrs utils.AttrLoadTpFromFolder,
|
||||
return err
|
||||
}
|
||||
if len(aps) != 0 && self.Sched != nil {
|
||||
utils.Logger.Info("ApierV1.LoadTariffPlanFromFolder, reloading scheduler.")
|
||||
utils.Logger.Info("ApierV2.LoadTariffPlanFromFolder, reloading scheduler.")
|
||||
self.Sched.Reload(true)
|
||||
}
|
||||
if len(cstKeys) != 0 && self.CdrStatsSrv != nil {
|
||||
if err := self.CdrStatsSrv.ReloadQueues(cstKeys, nil); err != nil {
|
||||
var out int
|
||||
if err := self.CdrStatsSrv.Call("CDRStatsV1.ReloadQueues", cstKeys, &out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(userKeys) != 0 && self.Users != nil {
|
||||
var r string
|
||||
if err := self.Users.ReloadUsers("", &r); err != nil {
|
||||
if err := self.Users.Call("UsersV1.ReloadUsers", "", &r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*reply = *li
|
||||
return nil
|
||||
}
|
||||
|
||||
type AttrGetActions struct {
|
||||
ActionIDs []string
|
||||
Offset int // Set the item offset
|
||||
Limit int // Limit number of items retrieved
|
||||
}
|
||||
|
||||
// Retrieves actions attached to specific ActionsId within cache
|
||||
func (self *ApierV2) GetActions(attr AttrGetActions, reply *map[string]engine.Actions) error {
|
||||
var actionKeys []string
|
||||
var err error
|
||||
if len(attr.ActionIDs) == 0 {
|
||||
if actionKeys, err = self.AccountDb.GetKeysForPrefix(utils.ACTION_PREFIX, false); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
for _, accID := range attr.ActionIDs {
|
||||
if len(accID) == 0 { // Source of error returned from redis (key not found)
|
||||
continue
|
||||
}
|
||||
actionKeys = append(actionKeys, utils.ACCOUNT_PREFIX+accID)
|
||||
}
|
||||
}
|
||||
if len(actionKeys) == 0 {
|
||||
return nil
|
||||
}
|
||||
if attr.Offset > len(actionKeys) {
|
||||
attr.Offset = len(actionKeys)
|
||||
}
|
||||
if attr.Offset < 0 {
|
||||
attr.Offset = 0
|
||||
}
|
||||
var limitedActions []string
|
||||
if attr.Limit != 0 {
|
||||
max := math.Min(float64(attr.Offset+attr.Limit), float64(len(actionKeys)))
|
||||
limitedActions = actionKeys[attr.Offset:int(max)]
|
||||
} else {
|
||||
limitedActions = actionKeys[attr.Offset:]
|
||||
}
|
||||
retActions := make(map[string]engine.Actions)
|
||||
for _, accKey := range limitedActions {
|
||||
key := accKey[len(utils.ACTION_PREFIX):]
|
||||
acts, err := self.RatingDb.GetActions(key, false)
|
||||
if err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
if len(acts) > 0 {
|
||||
retActions[key] = acts
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
*reply = retActions
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -247,6 +247,7 @@ func TestV2CDRsMySQLRateWithoutTP(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
//"d32a571d7bcbc6700fd35c1c0c5c6f458a62e260"
|
||||
rawCdrCGRID := utils.Sha1("bbb1", time.Date(2015, 11, 21, 10, 47, 24, 0, time.UTC).String())
|
||||
// Rate the injected CDR, should not rate it since we have no TP loaded
|
||||
attrs := utils.AttrRateCdrs{CgrIds: []string{rawCdrCGRID}}
|
||||
|
||||
@@ -18,7 +18,7 @@ type CacheItem struct {
|
||||
type ResponseCache struct {
|
||||
ttl time.Duration
|
||||
cache map[string]*CacheItem
|
||||
semaphore map[string]chan bool
|
||||
semaphore map[string]chan bool // used for waiting till the first goroutine processes the response
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ func NewResponseCache(ttl time.Duration) *ResponseCache {
|
||||
}
|
||||
|
||||
func (rc *ResponseCache) Cache(key string, item *CacheItem) {
|
||||
//utils.Logger.Info("key: " + key)
|
||||
if rc.ttl == 0 {
|
||||
return
|
||||
}
|
||||
@@ -54,13 +55,21 @@ func (rc *ResponseCache) Get(key string) (*CacheItem, error) {
|
||||
if rc.ttl == 0 {
|
||||
return nil, utils.ErrNotImplemented
|
||||
}
|
||||
rc.mu.RLock()
|
||||
item, ok := rc.cache[key]
|
||||
rc.mu.RUnlock()
|
||||
if ok {
|
||||
//utils.Logger.Info(",,,,,,,,,,,,,,,,,,,,,Found key: " + key)
|
||||
return item, nil
|
||||
}
|
||||
rc.wait(key) // wait for other goroutine processsing this key
|
||||
rc.mu.RLock()
|
||||
defer rc.mu.RUnlock()
|
||||
item, ok := rc.cache[key]
|
||||
item, ok = rc.cache[key]
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
//utils.Logger.Info("............................Found key: " + key)
|
||||
return item, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/rpcclient"
|
||||
"gopkg.in/fsnotify.v1"
|
||||
)
|
||||
|
||||
@@ -54,7 +55,7 @@ Common parameters within configs processed:
|
||||
Parameters specific per config instance:
|
||||
* duMultiplyFactor, cdrSourceId, cdrFilter, cdrFields
|
||||
*/
|
||||
func NewCdrc(cdrcCfgs map[string]*config.CdrcConfig, httpSkipTlsCheck bool, cdrs engine.Connector, closeChan chan struct{}, dfltTimezone string) (*Cdrc, error) {
|
||||
func NewCdrc(cdrcCfgs []*config.CdrcConfig, httpSkipTlsCheck bool, cdrs rpcclient.RpcClientConnection, closeChan chan struct{}, dfltTimezone string) (*Cdrc, error) {
|
||||
var cdrcCfg *config.CdrcConfig
|
||||
for _, cdrcCfg = range cdrcCfgs { // Take the first config out, does not matter which one
|
||||
break
|
||||
@@ -82,10 +83,10 @@ func NewCdrc(cdrcCfgs map[string]*config.CdrcConfig, httpSkipTlsCheck bool, cdrs
|
||||
|
||||
type Cdrc struct {
|
||||
httpSkipTlsCheck bool
|
||||
cdrcCfgs map[string]*config.CdrcConfig // All cdrc config profiles attached to this CDRC (key will be profile instance name)
|
||||
cdrcCfgs []*config.CdrcConfig // All cdrc config profiles attached to this CDRC (key will be profile instance name)
|
||||
dfltCdrcCfg *config.CdrcConfig
|
||||
timezone string
|
||||
cdrs engine.Connector
|
||||
cdrs rpcclient.RpcClientConnection
|
||||
httpClient *http.Client
|
||||
closeChan chan struct{} // Used to signal config reloads when we need to span different CDRC-Client
|
||||
maxOpenFiles chan struct{} // Maximum number of simultaneous files processed
|
||||
@@ -201,7 +202,7 @@ func (self *Cdrc) processFile(filePath string) error {
|
||||
utils.Logger.Info(fmt.Sprintf("<Cdrc> DryRun CDR: %+v", storedCdr))
|
||||
continue
|
||||
}
|
||||
if err := self.cdrs.ProcessCdr(storedCdr, &reply); err != nil {
|
||||
if err := self.cdrs.Call("Responder.ProcessCdr", storedCdr, &reply); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<Cdrc> Failed sending CDR, %+v, error: %s", storedCdr, err.Error()))
|
||||
} else if reply != "OK" {
|
||||
utils.Logger.Err(fmt.Sprintf("<Cdrc> Received unexpected reply for CDR, %+v, reply: %s", storedCdr, reply))
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2012-2015 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 cdrc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
/*
|
||||
README:
|
||||
|
||||
Enable local tests by passing '-local' to the go test command
|
||||
It is expected that the data folder of CGRateS exists at path /usr/share/cgrates/data or passed via command arguments.
|
||||
Prior running the tests, create database and users by running:
|
||||
mysql -pyourrootpwd < /usr/share/cgrates/data/storage/mysql/create_db_with_users.sql
|
||||
What these tests do:
|
||||
* Flush tables in storDb.
|
||||
* Start engine with default configuration and give it some time to listen (here caching can slow down).
|
||||
*
|
||||
*/
|
||||
|
||||
var cfgPath string
|
||||
var cfg *config.CGRConfig
|
||||
var cdrcCfgs map[string]*config.CdrcConfig
|
||||
var cdrcCfg *config.CdrcConfig
|
||||
|
||||
var testLocal = flag.Bool("local", false, "Perform the tests only on local test environment, not by default.") // This flag will be passed here via "go test -local" args
|
||||
var dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here")
|
||||
var storDbType = flag.String("stordb_type", "mysql", "The type of the storDb database <mysql>")
|
||||
var waitRater = flag.Int("wait_rater", 300, "Number of miliseconds to wait for rater to start and cache")
|
||||
|
||||
var fileContent1 = `accid11,prepaid,out,cgrates.org,call,1001,1001,+4986517174963,2013-02-03 19:54:00,62,supplier1,172.16.1.1
|
||||
accid12,prepaid,out,cgrates.org,call,1001,1001,+4986517174963,2013-02-03 19:54:00,62,supplier1,172.16.1.1
|
||||
dummy_data
|
||||
accid13,prepaid,out,cgrates.org,call,1001,1001,+4986517174963,2013-02-03 19:54:00,62,supplier1,172.16.1.1
|
||||
`
|
||||
|
||||
var fileContent2 = `accid21,prepaid,out,cgrates.org,call,1001,1001,+4986517174963,2013-02-03 19:54:00,62,supplier1,172.16.1.1
|
||||
accid22,prepaid,out,cgrates.org,call,1001,1001,+4986517174963,2013-02-03 19:54:00,62,supplier1,172.16.1.1
|
||||
#accid1,prepaid,out,cgrates.org,call,1001,1001,+4986517174963,2013-02-03 19:54:00,62,supplier1,172.16.1.1
|
||||
accid23,prepaid,out,cgrates.org,call,1001,1001,+4986517174963,2013-02-03 19:54:00,62,supplier1,172.16.1.1`
|
||||
|
||||
var fileContent3 = `accid31;prepaid;out;cgrates.org;call;1001;1001;+4986517174963;2013-02-03 19:54:00;62;supplier1;172.16.1.1
|
||||
accid32;prepaid;out;cgrates.org;call;1001;1001;+4986517174963;2013-02-03 19:54:00;62;supplier1;172.16.1.1
|
||||
#accid1;prepaid;out;cgrates.org;call;1001;1001;+4986517174963;2013-02-03 19:54:00;62;supplier1;172.16.1.1
|
||||
accid33;prepaid;out;cgrates.org;call;1001;1001;+4986517174963;2013-02-03 19:54:00;62;supplier1;172.16.1.1`
|
||||
|
||||
func startEngine() error {
|
||||
enginePath, err := exec.LookPath("cgr-engine")
|
||||
if err != nil {
|
||||
return errors.New("Cannot find cgr-engine executable")
|
||||
}
|
||||
stopEngine()
|
||||
engine := exec.Command(enginePath, "-config", cfgPath)
|
||||
if err := engine.Start(); err != nil {
|
||||
return fmt.Errorf("Cannot start cgr-engine: %s", err.Error())
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time to rater to fire up
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopEngine() error {
|
||||
exec.Command("pkill", "cgr-engine").Run() // Just to make sure another one is not running, bit brutal maybe we can fine tune it
|
||||
return nil
|
||||
}
|
||||
|
||||
// Need it here and not in init since Travis has no possibility to load local file
|
||||
func TestCsvLclLoadConfigt(*testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
cfgPath = path.Join(*dataDir, "conf", "samples", "apier")
|
||||
cfg, _ = config.NewCGRConfigFromFolder(cfgPath)
|
||||
if len(cfg.CdrcProfiles) > 0 {
|
||||
cdrcCfgs = cfg.CdrcProfiles["/var/log/cgrates/cdrc/in"]
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsvLclEmptyTables(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
if *storDbType != utils.MYSQL {
|
||||
t.Fatal("Unsupported storDbType")
|
||||
}
|
||||
mysql, err := engine.NewMySQLStorage(cfg.StorDBHost, cfg.StorDBPort, cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.StorDBMaxOpenConns, cfg.StorDBMaxIdleConns)
|
||||
if err != nil {
|
||||
t.Fatal("Error on opening database connection: ", err)
|
||||
}
|
||||
for _, scriptName := range []string{utils.CREATE_CDRS_TABLES_SQL, utils.CREATE_TARIFFPLAN_TABLES_SQL} {
|
||||
if err := mysql.CreateTablesFromScript(path.Join(*dataDir, "storage", *storDbType, scriptName)); err != nil {
|
||||
t.Fatal("Error on mysql creation: ", err.Error())
|
||||
return // No point in going further
|
||||
}
|
||||
}
|
||||
if _, err := mysql.Db.Query(fmt.Sprintf("SELECT 1 from %s", utils.TBL_CDRS)); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Creates cdr files and starts the engine
|
||||
func TestCsvLclCreateCdrFiles(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
if cdrcCfgs == nil {
|
||||
t.Fatal("Empty default cdrc configuration")
|
||||
}
|
||||
for _, cdrcCfg = range cdrcCfgs { // Take the first config out, does not matter which one
|
||||
break
|
||||
}
|
||||
if err := os.RemoveAll(cdrcCfg.CdrInDir); err != nil {
|
||||
t.Fatal("Error removing folder: ", cdrcCfg.CdrInDir, err)
|
||||
}
|
||||
if err := os.MkdirAll(cdrcCfg.CdrInDir, 0755); err != nil {
|
||||
t.Fatal("Error creating folder: ", cdrcCfg.CdrInDir, err)
|
||||
}
|
||||
if err := os.RemoveAll(cdrcCfg.CdrOutDir); err != nil {
|
||||
t.Fatal("Error removing folder: ", cdrcCfg.CdrOutDir, err)
|
||||
}
|
||||
if err := os.MkdirAll(cdrcCfg.CdrOutDir, 0755); err != nil {
|
||||
t.Fatal("Error creating folder: ", cdrcCfg.CdrOutDir, err)
|
||||
}
|
||||
if err := ioutil.WriteFile(path.Join(cdrcCfg.CdrInDir, "file1.csv"), []byte(fileContent1), 0644); err != nil {
|
||||
t.Fatal(err.Error)
|
||||
}
|
||||
if err := ioutil.WriteFile(path.Join(cdrcCfg.CdrInDir, "file2.csv"), []byte(fileContent2), 0644); err != nil {
|
||||
t.Fatal(err.Error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCsvLclProcessCdrDir(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
var cdrcCfg *config.CdrcConfig
|
||||
for _, cdrcCfg = range cdrcCfgs { // Take the first config out, does not matter which one
|
||||
break
|
||||
}
|
||||
if cdrcCfg.Cdrs == utils.INTERNAL { // For now we only test over network
|
||||
cdrcCfg.Cdrs = "127.0.0.1:2013"
|
||||
}
|
||||
if err := startEngine(); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
cdrc, err := NewCdrc(cdrcCfgs, true, nil, make(chan struct{}), "")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
if err := cdrc.processCdrDir(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
stopEngine()
|
||||
}
|
||||
|
||||
// Creates cdr files and starts the engine
|
||||
func TestCsvLclCreateCdr3File(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
if err := os.RemoveAll(cdrcCfg.CdrInDir); err != nil {
|
||||
t.Fatal("Error removing folder: ", cdrcCfg.CdrInDir, err)
|
||||
}
|
||||
if err := os.MkdirAll(cdrcCfg.CdrInDir, 0755); err != nil {
|
||||
t.Fatal("Error creating folder: ", cdrcCfg.CdrInDir, err)
|
||||
}
|
||||
if err := ioutil.WriteFile(path.Join(cdrcCfg.CdrInDir, "file3.csv"), []byte(fileContent3), 0644); err != nil {
|
||||
t.Fatal(err.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsvLclProcessCdr3Dir(t *testing.T) {
|
||||
if !*testLocal {
|
||||
return
|
||||
}
|
||||
if cdrcCfg.Cdrs == utils.INTERNAL { // For now we only test over network
|
||||
cdrcCfg.Cdrs = "127.0.0.1:2013"
|
||||
}
|
||||
if err := startEngine(); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
cdrc, err := NewCdrc(cdrcCfgs, true, nil, make(chan struct{}), "")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
if err := cdrc.processCdrDir(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
stopEngine()
|
||||
}
|
||||
@@ -156,7 +156,7 @@ BYE|3111f3c9|49ca4c42|a58ebaae40d08d6757d8424fb09c4c54@0:0:0:0:0:0:0:0|200|OK|14
|
||||
}}
|
||||
cdrc := &Cdrc{CdrFormat: utils.OSIPS_FLATSTORE, cdrSourceIds: []string{"TEST_CDRC"}, failedCallsPrefix: "missed_calls",
|
||||
cdrFields: cdrFields, partialRecords: make(map[string]map[string]*PartialFlatstoreRecord),
|
||||
guard: engine.NewGuardianLock()}
|
||||
guard: engine.Guardian}
|
||||
cdrsContent := bytes.NewReader([]byte(flatstoreCdrs))
|
||||
csvReader := csv.NewReader(cdrsContent)
|
||||
csvReader.Comma = '|'
|
||||
@@ -283,7 +283,7 @@ INVITE|324cb497|d4af7023|8deaadf2ae9a17809a391f05af31afb0@0:0:0:0:0:0:0:0|486|Bu
|
||||
}}
|
||||
cdrc := &Cdrc{CdrFormat: utils.OSIPS_FLATSTORE, cdrSourceIds: []string{"TEST_CDRC"}, failedCallsPrefix: "missed_calls",
|
||||
cdrFields: cdrFields, partialRecords: make(map[string]map[string]*PartialFlatstoreRecord),
|
||||
guard: engine.NewGuardianLock()}
|
||||
guard: engine.Guardian}
|
||||
cdrsContent := bytes.NewReader([]byte(flatstoreCdrs))
|
||||
csvReader := csv.NewReader(cdrsContent)
|
||||
csvReader.Comma = '|'
|
||||
|
||||
32
cdrc/csv.go
32
cdrc/csv.go
@@ -20,6 +20,7 @@ package cdrc
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -93,7 +94,7 @@ func pairToRecord(part1, part2 *PartialFlatstoreRecord) ([]string, error) {
|
||||
|
||||
func NewPartialRecordsCache(ttl time.Duration, cdrOutDir string, csvSep rune) (*PartialRecordsCache, error) {
|
||||
return &PartialRecordsCache{ttl: ttl, cdrOutDir: cdrOutDir, csvSep: csvSep,
|
||||
partialRecords: make(map[string]map[string]*PartialFlatstoreRecord), guard: engine.NewGuardianLock()}, nil
|
||||
partialRecords: make(map[string]map[string]*PartialFlatstoreRecord), guard: engine.Guardian}, nil
|
||||
}
|
||||
|
||||
type PartialRecordsCache struct {
|
||||
@@ -180,7 +181,7 @@ func (self *PartialRecordsCache) UncachePartial(fileName string, pr *PartialFlat
|
||||
}
|
||||
|
||||
func NewCsvRecordsProcessor(csvReader *csv.Reader, timezone, fileName string,
|
||||
dfltCdrcCfg *config.CdrcConfig, cdrcCfgs map[string]*config.CdrcConfig,
|
||||
dfltCdrcCfg *config.CdrcConfig, cdrcCfgs []*config.CdrcConfig,
|
||||
httpSkipTlsCheck bool, partialRecordsCache *PartialRecordsCache) *CsvRecordsProcessor {
|
||||
return &CsvRecordsProcessor{csvReader: csvReader, timezone: timezone, fileName: fileName,
|
||||
dfltCdrcCfg: dfltCdrcCfg, cdrcCfgs: cdrcCfgs,
|
||||
@@ -193,7 +194,7 @@ type CsvRecordsProcessor struct {
|
||||
timezone string // Timezone for CDRs which are not clearly specifying it
|
||||
fileName string
|
||||
dfltCdrcCfg *config.CdrcConfig
|
||||
cdrcCfgs map[string]*config.CdrcConfig
|
||||
cdrcCfgs []*config.CdrcConfig
|
||||
processedRecordsNr int64 // Number of content records in file
|
||||
httpSkipTlsCheck bool
|
||||
partialRecordsCache *PartialRecordsCache // Shared by cdrc so we can cache for all files in a folder
|
||||
@@ -246,8 +247,8 @@ func (self *CsvRecordsProcessor) processPartialRecord(record []string) ([]string
|
||||
|
||||
// Takes the record from a slice and turns it into StoredCdrs, posting them to the cdrServer
|
||||
func (self *CsvRecordsProcessor) processRecord(record []string) ([]*engine.CDR, error) {
|
||||
recordCdrs := make([]*engine.CDR, 0) // More CDRs based on the number of filters and field templates
|
||||
for cdrcId, cdrcCfg := range self.cdrcCfgs { // cdrFields coming from more templates will produce individual storCdr records
|
||||
recordCdrs := make([]*engine.CDR, 0) // More CDRs based on the number of filters and field templates
|
||||
for _, cdrcCfg := range self.cdrcCfgs { // cdrFields coming from more templates will produce individual storCdr records
|
||||
// Make sure filters are matching
|
||||
filterBreak := false
|
||||
for _, rsrFilter := range cdrcCfg.CdrFilter {
|
||||
@@ -264,12 +265,12 @@ func (self *CsvRecordsProcessor) processRecord(record []string) ([]*engine.CDR,
|
||||
if filterBreak { // Stop importing cdrc fields profile due to non matching filter
|
||||
continue
|
||||
}
|
||||
if storedCdr, err := self.recordToStoredCdr(record, cdrcId); err != nil {
|
||||
if storedCdr, err := self.recordToStoredCdr(record, cdrcCfg); err != nil {
|
||||
return nil, fmt.Errorf("Failed converting to StoredCdr, error: %s", err.Error())
|
||||
} else {
|
||||
recordCdrs = append(recordCdrs, storedCdr)
|
||||
}
|
||||
if !self.cdrcCfgs[cdrcId].ContinueOnSuccess {
|
||||
if !cdrcCfg.ContinueOnSuccess {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -277,11 +278,11 @@ func (self *CsvRecordsProcessor) processRecord(record []string) ([]*engine.CDR,
|
||||
}
|
||||
|
||||
// Takes the record out of csv and turns it into storedCdr which can be processed by CDRS
|
||||
func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcId string) (*engine.CDR, error) {
|
||||
storedCdr := &engine.CDR{OriginHost: "0.0.0.0", Source: self.cdrcCfgs[cdrcId].CdrSourceId, ExtraFields: make(map[string]string), Cost: -1}
|
||||
func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcCfg *config.CdrcConfig) (*engine.CDR, error) {
|
||||
storedCdr := &engine.CDR{OriginHost: "0.0.0.0", Source: cdrcCfg.CdrSourceId, ExtraFields: make(map[string]string), Cost: -1}
|
||||
var err error
|
||||
var lazyHttpFields []*config.CfgCdrField
|
||||
for _, cdrFldCfg := range self.cdrcCfgs[cdrcId].ContentFields {
|
||||
for _, cdrFldCfg := range cdrcCfg.ContentFields {
|
||||
if utils.IsSliceMember([]string{utils.KAM_FLATSTORE, utils.OSIPS_FLATSTORE}, self.dfltCdrcCfg.CdrFormat) { // Hardcode some values in case of flatstore
|
||||
switch cdrFldCfg.FieldId {
|
||||
case utils.ACCID:
|
||||
@@ -314,8 +315,8 @@ func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcId strin
|
||||
}
|
||||
}
|
||||
storedCdr.CGRID = utils.Sha1(storedCdr.OriginID, storedCdr.SetupTime.UTC().String())
|
||||
if storedCdr.ToR == utils.DATA && self.cdrcCfgs[cdrcId].DataUsageMultiplyFactor != 0 {
|
||||
storedCdr.Usage = time.Duration(float64(storedCdr.Usage.Nanoseconds()) * self.cdrcCfgs[cdrcId].DataUsageMultiplyFactor)
|
||||
if storedCdr.ToR == utils.DATA && cdrcCfg.DataUsageMultiplyFactor != 0 {
|
||||
storedCdr.Usage = time.Duration(float64(storedCdr.Usage.Nanoseconds()) * cdrcCfg.DataUsageMultiplyFactor)
|
||||
}
|
||||
for _, httpFieldCfg := range lazyHttpFields { // Lazy process the http fields
|
||||
var outValByte []byte
|
||||
@@ -323,7 +324,12 @@ func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcId strin
|
||||
for _, rsrFld := range httpFieldCfg.Value {
|
||||
httpAddr += rsrFld.ParseValue("")
|
||||
}
|
||||
if outValByte, err = utils.HttpJsonPost(httpAddr, self.httpSkipTlsCheck, storedCdr); err != nil && httpFieldCfg.Mandatory {
|
||||
var jsn []byte
|
||||
jsn, err = json.Marshal(storedCdr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if outValByte, err = utils.HttpJsonPost(httpAddr, self.httpSkipTlsCheck, jsn); err != nil && httpFieldCfg.Mandatory {
|
||||
return nil, err
|
||||
} else {
|
||||
fieldVal = string(outValByte)
|
||||
|
||||
201
cdrc/csv_it_test.go
Normal file
201
cdrc/csv_it_test.go
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2012-2015 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 cdrc
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
/*
|
||||
README:
|
||||
|
||||
Enable local tests by passing '-local' to the go test command
|
||||
It is expected that the data folder of CGRateS exists at path /usr/share/cgrates/data or passed via command arguments.
|
||||
Prior running the tests, create database and users by running:
|
||||
mysql -pyourrootpwd < /usr/share/cgrates/data/storage/mysql/create_db_with_users.sql
|
||||
What these tests do:
|
||||
* Flush tables in storDb.
|
||||
* Start engine with default configuration and give it some time to listen (here caching can slow down).
|
||||
*
|
||||
*/
|
||||
|
||||
var csvCfgPath string
|
||||
var csvCfg *config.CGRConfig
|
||||
var cdrcCfgs []*config.CdrcConfig
|
||||
var cdrcCfg *config.CdrcConfig
|
||||
var cdrcRpc *rpc.Client
|
||||
|
||||
var testLocal = flag.Bool("local", false, "Perform the tests only on local test environment, not by default.") // This flag will be passed here via "go test -local" args
|
||||
var testIT = flag.Bool("integration", false, "Perform the tests only on local test environment, not by default.") // This flag will be passed here via "go test -local" args
|
||||
var dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here")
|
||||
var waitRater = flag.Int("wait_rater", 300, "Number of miliseconds to wait for rater to start and cache")
|
||||
|
||||
var fileContent1 = `dbafe9c8614c785a65aabd116dd3959c3c56f7f6,default,*voice,dsafdsaf,*rated,*out,cgrates.org,call,1001,1001,+4986517174963,2013-11-07 08:42:25 +0000 UTC,2013-11-07 08:42:26 +0000 UTC,10s,1.0100,val_extra3,"",val_extra1
|
||||
dbafe9c8614c785a65aabd116dd3959c3c56f7f7,default,*voice,dsafdsag,*rated,*out,cgrates.org,call,1001,1001,+4986517174964,2013-11-07 09:42:25 +0000 UTC,2013-11-07 09:42:26 +0000 UTC,20s,1.0100,val_extra3,"",val_extra1
|
||||
`
|
||||
|
||||
var fileContent2 = `accid21;*prepaid;itsyscom.com;1001;086517174963;2013-02-03 19:54:00;62;val_extra3;"";val_extra1
|
||||
accid22;*postpaid;itsyscom.com;1001;+4986517174963;2013-02-03 19:54:00;123;val_extra3;"";val_extra1
|
||||
#accid1;*pseudoprepaid;itsyscom.com;1001;+4986517174963;2013-02-03 19:54:00;12;val_extra3;"";val_extra1
|
||||
accid23;*rated;cgrates.org;1001;086517174963;2013-02-03 19:54:00;26;val_extra3;"";val_extra1`
|
||||
|
||||
func TestCsvITInitConfig(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
var err error
|
||||
csvCfgPath = path.Join(*dataDir, "conf", "samples", "cdrccsv")
|
||||
if csvCfg, err = config.NewCGRConfigFromFolder(csvCfgPath); err != nil {
|
||||
t.Fatal("Got config error: ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// InitDb so we can rely on count
|
||||
func TestCsvITInitCdrDb(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
if err := engine.InitStorDb(csvCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsvITCreateCdrDirs(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
for _, cdrcProfiles := range csvCfg.CdrcProfiles {
|
||||
for _, cdrcInst := range cdrcProfiles {
|
||||
for _, dir := range []string{cdrcInst.CdrInDir, cdrcInst.CdrOutDir} {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Fatal("Error removing folder: ", dir, err)
|
||||
}
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
t.Fatal("Error creating folder: ", dir, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsvITStartEngine(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
if _, err := engine.StopStartEngine(csvCfgPath, *waitRater); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestCsvITRpcConn(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
var err error
|
||||
cdrcRpc, err = jsonrpc.Dial("tcp", csvCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
t.Fatal("Could not connect to rater: ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// The default scenario, out of cdrc defined in .cfg file
|
||||
func TestCsvITHandleCdr1File(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
fileName := "file1.csv"
|
||||
tmpFilePath := path.Join("/tmp", fileName)
|
||||
if err := ioutil.WriteFile(tmpFilePath, []byte(fileContent1), 0644); err != nil {
|
||||
t.Fatal(err.Error)
|
||||
}
|
||||
if err := os.Rename(tmpFilePath, path.Join("/tmp/cdrctests/csvit1/in", fileName)); err != nil {
|
||||
t.Fatal("Error moving file to processing directory: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Scenario out of first .xml config
|
||||
func TestCsvITHandleCdr2File(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
fileName := "file2.csv"
|
||||
tmpFilePath := path.Join("/tmp", fileName)
|
||||
if err := ioutil.WriteFile(tmpFilePath, []byte(fileContent2), 0644); err != nil {
|
||||
t.Fatal(err.Error)
|
||||
}
|
||||
if err := os.Rename(tmpFilePath, path.Join("/tmp/cdrctests/csvit2/in", fileName)); err != nil {
|
||||
t.Fatal("Error moving file to processing directory: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsvITProcessedFiles(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Duration(2**waitRater) * time.Millisecond)
|
||||
if outContent1, err := ioutil.ReadFile("/tmp/cdrctests/csvit1/out/file1.csv"); err != nil {
|
||||
t.Error(err)
|
||||
} else if fileContent1 != string(outContent1) {
|
||||
t.Errorf("Expecting: %q, received: %q", fileContent1, string(outContent1))
|
||||
}
|
||||
if outContent2, err := ioutil.ReadFile("/tmp/cdrctests/csvit2/out/file2.csv"); err != nil {
|
||||
t.Error(err)
|
||||
} else if fileContent2 != string(outContent2) {
|
||||
t.Errorf("Expecting: %q, received: %q", fileContent1, string(outContent2))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsvITAnalyseCDRs(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
var reply []*engine.ExternalCDR
|
||||
if err := cdrcRpc.Call("ApierV2.GetCdrs", utils.RPCCDRsFilter{}, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 6 { // 1 injected, 1 rated, 1 *raw and it's pair in *default run
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
}
|
||||
if err := cdrcRpc.Call("ApierV2.GetCdrs", utils.RPCCDRsFilter{DestinationPrefixes: []string{"08651"}}, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 0 { // Original 08651 was converted
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCsvITKillEngine(t *testing.T) {
|
||||
if !*testIT {
|
||||
return
|
||||
}
|
||||
if err := engine.KillEngine(*waitRater); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -30,21 +30,21 @@ import (
|
||||
|
||||
func TestCsvRecordForkCdr(t *testing.T) {
|
||||
cgrConfig, _ := config.NewDefaultCGRConfig()
|
||||
cdrcConfig := cgrConfig.CdrcProfiles["/var/log/cgrates/cdrc/in"][utils.META_DEFAULT]
|
||||
cdrcConfig := cgrConfig.CdrcProfiles["/var/log/cgrates/cdrc/in"][0]
|
||||
cdrcConfig.CdrSourceId = "TEST_CDRC"
|
||||
cdrcConfig.ContentFields = append(cdrcConfig.ContentFields, &config.CfgCdrField{Tag: "SupplierTest", Type: utils.META_COMPOSED, FieldId: utils.SUPPLIER, Value: []*utils.RSRField{&utils.RSRField{Id: "14"}}})
|
||||
cdrcConfig.ContentFields = append(cdrcConfig.ContentFields, &config.CfgCdrField{Tag: "DisconnectCauseTest", Type: utils.META_COMPOSED, FieldId: utils.DISCONNECT_CAUSE,
|
||||
Value: []*utils.RSRField{&utils.RSRField{Id: "16"}}})
|
||||
//
|
||||
csvProcessor := &CsvRecordsProcessor{dfltCdrcCfg: cdrcConfig, cdrcCfgs: map[string]*config.CdrcConfig{"*default": cdrcConfig}}
|
||||
csvProcessor := &CsvRecordsProcessor{dfltCdrcCfg: cdrcConfig, cdrcCfgs: []*config.CdrcConfig{cdrcConfig}}
|
||||
cdrRow := []string{"firstField", "secondField"}
|
||||
_, err := csvProcessor.recordToStoredCdr(cdrRow, "*default")
|
||||
_, err := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig)
|
||||
if err == nil {
|
||||
t.Error("Failed to corectly detect missing fields from record")
|
||||
}
|
||||
cdrRow = []string{"ignored", "ignored", utils.VOICE, "acc1", utils.META_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", "NORMAL_DISCONNECT"}
|
||||
rtCdr, err := csvProcessor.recordToStoredCdr(cdrRow, "*default")
|
||||
rtCdr, err := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig)
|
||||
if err != nil {
|
||||
t.Error("Failed to parse CDR in rated cdr", err)
|
||||
}
|
||||
@@ -76,14 +76,14 @@ func TestCsvRecordForkCdr(t *testing.T) {
|
||||
|
||||
func TestCsvDataMultiplyFactor(t *testing.T) {
|
||||
cgrConfig, _ := config.NewDefaultCGRConfig()
|
||||
cdrcConfig := cgrConfig.CdrcProfiles["/var/log/cgrates/cdrc/in"][utils.META_DEFAULT]
|
||||
cdrcConfig := cgrConfig.CdrcProfiles["/var/log/cgrates/cdrc/in"][0]
|
||||
cdrcConfig.CdrSourceId = "TEST_CDRC"
|
||||
cdrcConfig.ContentFields = []*config.CfgCdrField{&config.CfgCdrField{Tag: "TORField", Type: utils.META_COMPOSED, FieldId: utils.TOR, Value: []*utils.RSRField{&utils.RSRField{Id: "0"}}},
|
||||
&config.CfgCdrField{Tag: "UsageField", Type: utils.META_COMPOSED, FieldId: utils.USAGE, Value: []*utils.RSRField{&utils.RSRField{Id: "1"}}}}
|
||||
csvProcessor := &CsvRecordsProcessor{dfltCdrcCfg: cdrcConfig, cdrcCfgs: map[string]*config.CdrcConfig{"*default": cdrcConfig}}
|
||||
csvProcessor.cdrcCfgs["*default"].DataUsageMultiplyFactor = 0
|
||||
csvProcessor := &CsvRecordsProcessor{dfltCdrcCfg: cdrcConfig, cdrcCfgs: []*config.CdrcConfig{cdrcConfig}}
|
||||
csvProcessor.cdrcCfgs[0].DataUsageMultiplyFactor = 0
|
||||
cdrRow := []string{"*data", "1"}
|
||||
rtCdr, err := csvProcessor.recordToStoredCdr(cdrRow, "*default")
|
||||
rtCdr, err := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig)
|
||||
if err != nil {
|
||||
t.Error("Failed to parse CDR in rated cdr", err)
|
||||
}
|
||||
@@ -100,7 +100,7 @@ func TestCsvDataMultiplyFactor(t *testing.T) {
|
||||
if !reflect.DeepEqual(expectedCdr, rtCdr) {
|
||||
t.Errorf("Expected: \n%v, \nreceived: \n%v", expectedCdr, rtCdr)
|
||||
}
|
||||
csvProcessor.cdrcCfgs["*default"].DataUsageMultiplyFactor = 1024
|
||||
csvProcessor.cdrcCfgs[0].DataUsageMultiplyFactor = 1024
|
||||
expectedCdr = &engine.CDR{
|
||||
CGRID: utils.Sha1("", sTime.String()),
|
||||
ToR: cdrRow[0],
|
||||
@@ -110,7 +110,7 @@ func TestCsvDataMultiplyFactor(t *testing.T) {
|
||||
ExtraFields: map[string]string{},
|
||||
Cost: -1,
|
||||
}
|
||||
if rtCdr, _ := csvProcessor.recordToStoredCdr(cdrRow, "*default"); !reflect.DeepEqual(expectedCdr, rtCdr) {
|
||||
if rtCdr, _ := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig); !reflect.DeepEqual(expectedCdr, rtCdr) {
|
||||
t.Errorf("Expected: \n%v, \nreceived: \n%v", expectedCdr, rtCdr)
|
||||
}
|
||||
cdrRow = []string{"*voice", "1"}
|
||||
@@ -123,7 +123,7 @@ func TestCsvDataMultiplyFactor(t *testing.T) {
|
||||
ExtraFields: map[string]string{},
|
||||
Cost: -1,
|
||||
}
|
||||
if rtCdr, _ := csvProcessor.recordToStoredCdr(cdrRow, "*default"); !reflect.DeepEqual(expectedCdr, rtCdr) {
|
||||
if rtCdr, _ := csvProcessor.recordToStoredCdr(cdrRow, cdrcConfig); !reflect.DeepEqual(expectedCdr, rtCdr) {
|
||||
t.Errorf("Expected: \n%v, \nreceived: \n%v", expectedCdr, rtCdr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,11 @@ func TestFlatstoreLclCreateCdrFiles(t *testing.T) {
|
||||
if flatstoreCfg == nil {
|
||||
t.Fatal("Empty default cdrc configuration")
|
||||
}
|
||||
flatstoreCdrcCfg = flatstoreCfg.CdrcProfiles["/tmp/cgr_flatstore/cdrc/in"]["FLATSTORE"]
|
||||
for _, cdrcCfg := range flatstoreCfg.CdrcProfiles["/tmp/cgr_flatstore/cdrc/in"] {
|
||||
if cdrcCfg.ID == "FLATSTORE" {
|
||||
flatstoreCdrcCfg = cdrcCfg
|
||||
}
|
||||
}
|
||||
if err := os.RemoveAll(flatstoreCdrcCfg.CdrInDir); err != nil {
|
||||
t.Fatal("Error removing folder: ", flatstoreCdrcCfg.CdrInDir, err)
|
||||
}
|
||||
|
||||
47
cdrc/fwv.go
47
cdrc/fwv.go
@@ -20,16 +20,18 @@ package cdrc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func fwvValue(cdrLine string, indexStart, width int, padding string) string {
|
||||
@@ -47,14 +49,14 @@ func fwvValue(cdrLine string, indexStart, width int, padding string) string {
|
||||
return rawVal
|
||||
}
|
||||
|
||||
func NewFwvRecordsProcessor(file *os.File, dfltCfg *config.CdrcConfig, cdrcCfgs map[string]*config.CdrcConfig, httpClient *http.Client, httpSkipTlsCheck bool, timezone string) *FwvRecordsProcessor {
|
||||
func NewFwvRecordsProcessor(file *os.File, dfltCfg *config.CdrcConfig, cdrcCfgs []*config.CdrcConfig, httpClient *http.Client, httpSkipTlsCheck bool, timezone string) *FwvRecordsProcessor {
|
||||
return &FwvRecordsProcessor{file: file, cdrcCfgs: cdrcCfgs, dfltCfg: dfltCfg, httpSkipTlsCheck: httpSkipTlsCheck, timezone: timezone}
|
||||
}
|
||||
|
||||
type FwvRecordsProcessor struct {
|
||||
file *os.File
|
||||
dfltCfg *config.CdrcConfig // General parameters
|
||||
cdrcCfgs map[string]*config.CdrcConfig
|
||||
cdrcCfgs []*config.CdrcConfig
|
||||
httpClient *http.Client
|
||||
httpSkipTlsCheck bool
|
||||
timezone string
|
||||
@@ -123,11 +125,11 @@ func (self *FwvRecordsProcessor) ProcessNextRecord() ([]*engine.CDR, error) {
|
||||
}
|
||||
self.processedRecordsNr += 1
|
||||
record := string(buf)
|
||||
for cfgKey, cdrcCfg := range self.cdrcCfgs {
|
||||
if passes := self.recordPassesCfgFilter(record, cfgKey); !passes {
|
||||
for _, cdrcCfg := range self.cdrcCfgs {
|
||||
if passes := self.recordPassesCfgFilter(record, cdrcCfg); !passes {
|
||||
continue
|
||||
}
|
||||
if storedCdr, err := self.recordToStoredCdr(record, cfgKey); err != nil {
|
||||
if storedCdr, err := self.recordToStoredCdr(record, cdrcCfg, cdrcCfg.ID); err != nil {
|
||||
return nil, fmt.Errorf("Failed converting to StoredCdr, error: %s", err.Error())
|
||||
} else {
|
||||
recordCdrs = append(recordCdrs, storedCdr)
|
||||
@@ -139,9 +141,9 @@ func (self *FwvRecordsProcessor) ProcessNextRecord() ([]*engine.CDR, error) {
|
||||
return recordCdrs, nil
|
||||
}
|
||||
|
||||
func (self *FwvRecordsProcessor) recordPassesCfgFilter(record, configKey string) bool {
|
||||
func (self *FwvRecordsProcessor) recordPassesCfgFilter(record string, cdrcCfg *config.CdrcConfig) bool {
|
||||
filterPasses := true
|
||||
for _, rsrFilter := range self.cdrcCfgs[configKey].CdrFilter {
|
||||
for _, rsrFilter := range cdrcCfg.CdrFilter {
|
||||
if rsrFilter == nil { // Nil filter does not need to match anything
|
||||
continue
|
||||
}
|
||||
@@ -156,8 +158,8 @@ func (self *FwvRecordsProcessor) recordPassesCfgFilter(record, configKey string)
|
||||
return filterPasses
|
||||
}
|
||||
|
||||
// Converts a record (header or normal) to StoredCdr
|
||||
func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cfgKey string) (*engine.CDR, error) {
|
||||
// Converts a record (header or normal) to CDR
|
||||
func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cdrcCfg *config.CdrcConfig, cfgKey string) (*engine.CDR, error) {
|
||||
var err error
|
||||
var lazyHttpFields []*config.CfgCdrField
|
||||
var cfgFields []*config.CfgCdrField
|
||||
@@ -169,13 +171,13 @@ func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cfgKey string)
|
||||
storedCdr = &engine.CDR{OriginHost: "0.0.0.0", ExtraFields: make(map[string]string), Cost: -1}
|
||||
}
|
||||
if cfgKey == "*header" {
|
||||
cfgFields = self.dfltCfg.HeaderFields
|
||||
storedCdr.Source = self.dfltCfg.CdrSourceId
|
||||
duMultiplyFactor = self.dfltCfg.DataUsageMultiplyFactor
|
||||
cfgFields = cdrcCfg.HeaderFields
|
||||
storedCdr.Source = cdrcCfg.CdrSourceId
|
||||
duMultiplyFactor = cdrcCfg.DataUsageMultiplyFactor
|
||||
} else {
|
||||
cfgFields = self.cdrcCfgs[cfgKey].ContentFields
|
||||
storedCdr.Source = self.cdrcCfgs[cfgKey].CdrSourceId
|
||||
duMultiplyFactor = self.cdrcCfgs[cfgKey].DataUsageMultiplyFactor
|
||||
cfgFields = cdrcCfg.ContentFields
|
||||
storedCdr.Source = cdrcCfg.CdrSourceId
|
||||
duMultiplyFactor = cdrcCfg.DataUsageMultiplyFactor
|
||||
}
|
||||
for _, cdrFldCfg := range cfgFields {
|
||||
var fieldVal string
|
||||
@@ -214,7 +216,12 @@ func (self *FwvRecordsProcessor) recordToStoredCdr(record string, cfgKey string)
|
||||
for _, rsrFld := range httpFieldCfg.Value {
|
||||
httpAddr += rsrFld.ParseValue("")
|
||||
}
|
||||
if outValByte, err = utils.HttpJsonPost(httpAddr, self.httpSkipTlsCheck, storedCdr); err != nil && httpFieldCfg.Mandatory {
|
||||
var jsn []byte
|
||||
jsn, err = json.Marshal(storedCdr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if outValByte, err = utils.HttpJsonPost(httpAddr, self.httpSkipTlsCheck, jsn); err != nil && httpFieldCfg.Mandatory {
|
||||
return nil, err
|
||||
} else {
|
||||
fieldVal = string(outValByte)
|
||||
@@ -237,7 +244,7 @@ func (self *FwvRecordsProcessor) processHeader() error {
|
||||
return fmt.Errorf("In header, line len: %d, have read: %d", self.lineLen, nRead)
|
||||
}
|
||||
var err error
|
||||
if self.headerCdr, err = self.recordToStoredCdr(string(buf), "*header"); err != nil {
|
||||
if self.headerCdr, err = self.recordToStoredCdr(string(buf), self.dfltCfg, "*header"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -19,8 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package cdrc
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"io/ioutil"
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
@@ -28,6 +26,9 @@ import (
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
)
|
||||
|
||||
var fwvCfgPath string
|
||||
@@ -91,7 +92,11 @@ func TestFwvLclCreateCdrFiles(t *testing.T) {
|
||||
if fwvCfg == nil {
|
||||
t.Fatal("Empty default cdrc configuration")
|
||||
}
|
||||
fwvCdrcCfg = fwvCfg.CdrcProfiles["/tmp/cgr_fwv/cdrc/in"]["FWV1"]
|
||||
for _, cdrcCfg := range fwvCfg.CdrcProfiles["/tmp/cgr_fwv/cdrc/in"] {
|
||||
if cdrcCfg.ID == "FWV1" {
|
||||
fwvCdrcCfg = cdrcCfg
|
||||
}
|
||||
}
|
||||
if err := os.RemoveAll(fwvCdrcCfg.CdrInDir); err != nil {
|
||||
t.Fatal("Error removing folder: ", fwvCdrcCfg.CdrInDir, err)
|
||||
}
|
||||
|
||||
@@ -45,11 +45,11 @@ func TestFwvValue(t *testing.T) {
|
||||
func TestFwvRecordPassesCfgFilter(t *testing.T) {
|
||||
//record, configKey string) bool {
|
||||
cgrConfig, _ := config.NewDefaultCGRConfig()
|
||||
cdrcConfig := cgrConfig.CdrcProfiles["/var/log/cgrates/cdrc/in"][utils.META_DEFAULT] // We don't really care that is for .csv since all we want to test are the filters
|
||||
cdrcConfig := cgrConfig.CdrcProfiles["/var/log/cgrates/cdrc/in"][0] // We don't really care that is for .csv since all we want to test are the filters
|
||||
cdrcConfig.CdrFilter = utils.ParseRSRFieldsMustCompile(`~52:s/^0(\d{9})/+49${1}/(^+49123123120)`, utils.INFIELD_SEP)
|
||||
fwvRp := &FwvRecordsProcessor{cdrcCfgs: cgrConfig.CdrcProfiles["/var/log/cgrates/cdrc/in"]}
|
||||
cdrLine := "CDR0000010 0 20120708181506000123451234 0040123123120 004 000018009980010001ISDN ABC 10Buiten uw regio EHV 00000009190000000009"
|
||||
if passesFilter := fwvRp.recordPassesCfgFilter(cdrLine, utils.META_DEFAULT); !passesFilter {
|
||||
if passesFilter := fwvRp.recordPassesCfgFilter(cdrLine, cdrcConfig); !passesFilter {
|
||||
t.Error("Not passes filter")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,13 +116,13 @@ type CdrExporter struct {
|
||||
// Return Json marshaled callCost attached to
|
||||
// Keep it separately so we test only this part in local tests
|
||||
func (cdre *CdrExporter) getCdrCostDetails(CGRID, runId string) (string, error) {
|
||||
cc, err := cdre.cdrDb.GetCallCostLog(CGRID, runId)
|
||||
smcs, err := cdre.cdrDb.GetSMCosts(CGRID, runId, "", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if cc == nil {
|
||||
} else if len(smcs) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
ccJson, _ := json.Marshal(cc)
|
||||
ccJson, _ := json.Marshal(smcs[0].CostDetails)
|
||||
return string(ccJson), nil
|
||||
}
|
||||
|
||||
@@ -352,9 +352,13 @@ func (cdre *CdrExporter) processCdr(cdr *engine.CDR) error {
|
||||
case utils.META_HTTP_POST:
|
||||
var outValByte []byte
|
||||
httpAddr := cfgFld.Value.Id()
|
||||
jsn, err := json.Marshal(cdr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(httpAddr) == 0 {
|
||||
err = fmt.Errorf("Empty http address for field %s type %s", cfgFld.Tag, cfgFld.Type)
|
||||
} else if outValByte, err = utils.HttpJsonPost(httpAddr, cdre.httpSkipTlsCheck, cdr); err == nil {
|
||||
} else if outValByte, err = utils.HttpJsonPost(httpAddr, cdre.httpSkipTlsCheck, jsn); err == nil {
|
||||
outVal = string(outValByte)
|
||||
if len(outVal) == 0 && cfgFld.Mandatory {
|
||||
err = fmt.Errorf("Empty result for http_post field: %s", cfgFld.Tag)
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
// _ "net/http/pprof"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
@@ -71,7 +71,7 @@ var (
|
||||
err error
|
||||
)
|
||||
|
||||
func startCdrcs(internalCdrSChan chan *engine.CdrServer, internalRaterChan chan *engine.Responder, exitChan chan bool) {
|
||||
func startCdrcs(internalCdrSChan, internalRaterChan chan rpcclient.RpcClientConnection, exitChan chan bool) {
|
||||
cdrcInitialized := false // Control whether the cdrc was already initialized (so we don't reload in that case)
|
||||
var cdrcChildrenChan chan struct{} // Will use it to communicate with the children of one fork
|
||||
for {
|
||||
@@ -87,42 +87,34 @@ func startCdrcs(internalCdrSChan chan *engine.CdrServer, internalRaterChan chan
|
||||
}
|
||||
// Start CDRCs
|
||||
for _, cdrcCfgs := range cfg.CdrcProfiles {
|
||||
var cdrcCfg *config.CdrcConfig
|
||||
for _, cdrcCfg = range cdrcCfgs { // Take a random config out since they should be the same
|
||||
break
|
||||
var enabledCfgs []*config.CdrcConfig
|
||||
for _, cdrcCfg := range cdrcCfgs { // Take a random config out since they should be the same
|
||||
if cdrcCfg.Enabled {
|
||||
enabledCfgs = append(enabledCfgs, cdrcCfg)
|
||||
}
|
||||
}
|
||||
if cdrcCfg.Enabled == false {
|
||||
continue // Ignore not enabled
|
||||
|
||||
if len(enabledCfgs) != 0 {
|
||||
go startCdrc(internalCdrSChan, internalRaterChan, cdrcCfgs, cfg.HttpSkipTlsVerify, cdrcChildrenChan, exitChan)
|
||||
}
|
||||
go startCdrc(internalCdrSChan, internalRaterChan, cdrcCfgs, cfg.HttpSkipTlsVerify, cdrcChildrenChan, exitChan)
|
||||
}
|
||||
cdrcInitialized = true // Initialized
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Fires up a cdrc instance
|
||||
func startCdrc(internalCdrSChan chan *engine.CdrServer, internalRaterChan chan *engine.Responder, cdrcCfgs map[string]*config.CdrcConfig, httpSkipTlsCheck bool,
|
||||
func startCdrc(internalCdrSChan, internalRaterChan chan rpcclient.RpcClientConnection, cdrcCfgs []*config.CdrcConfig, httpSkipTlsCheck bool,
|
||||
closeChan chan struct{}, exitChan chan bool) {
|
||||
var cdrsConn engine.Connector
|
||||
var cdrcCfg *config.CdrcConfig
|
||||
for _, cdrcCfg = range cdrcCfgs { // Take the first config out, does not matter which one
|
||||
break
|
||||
}
|
||||
if cdrcCfg.Cdrs == utils.INTERNAL {
|
||||
cdrsChan := <-internalCdrSChan // This will signal that the cdrs part is populated in internalRaterChan
|
||||
internalCdrSChan <- cdrsChan // Put it back for other components
|
||||
resp := <-internalRaterChan
|
||||
cdrsConn = resp
|
||||
internalRaterChan <- resp
|
||||
} else {
|
||||
conn, err := rpcclient.NewRpcClient("tcp", cdrcCfg.Cdrs, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRC> Could not connect to CDRS via RPC: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
cdrsConn = &engine.RPCClientConnector{Client: conn}
|
||||
cdrsConn, err := engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cdrcCfg.CdrsConns, internalCdrSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRC> Could not connect to CDRS via RPC: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
cdrc, err := cdrc.NewCdrc(cdrcCfgs, httpSkipTlsCheck, cdrsConn, closeChan, cfg.DefaultTimezone)
|
||||
if err != nil {
|
||||
@@ -136,51 +128,31 @@ func startCdrc(internalCdrSChan chan *engine.CdrServer, internalRaterChan chan *
|
||||
}
|
||||
}
|
||||
|
||||
func startSmGeneric(internalSMGChan chan rpcclient.RpcClientConnection, internalRaterChan chan *engine.Responder, server *utils.Server, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS SM-Generic service.")
|
||||
var raterConn, cdrsConn engine.Connector
|
||||
var client *rpcclient.RpcClient
|
||||
var err error
|
||||
// Connect to rater
|
||||
for _, raterCfg := range cfg.SmGenericConfig.HaRater {
|
||||
if raterCfg.Server == utils.INTERNAL {
|
||||
resp := <-internalRaterChan
|
||||
raterConn = resp // Will overwrite here for the sake of keeping internally the new configuration format for ha connections
|
||||
internalRaterChan <- resp
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", raterCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil { //Connected so no need to reiterate
|
||||
utils.Logger.Crit(fmt.Sprintf("<SM-Generic> Could not connect to Rater via RPC: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
raterConn = &engine.RPCClientConnector{Client: client}
|
||||
func startSmGeneric(internalSMGChan chan rpcclient.RpcClientConnection, internalRaterChan, internalCDRSChan chan rpcclient.RpcClientConnection, server *utils.Server, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS SMGeneric service.")
|
||||
var ralsConns, cdrsConn *rpcclient.RpcClientPool
|
||||
if len(cfg.SmGenericConfig.RALsConns) != 0 {
|
||||
ralsConns, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.SmGenericConfig.RALsConns, internalRaterChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SMGeneric> Could not connect to RAL: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
// Connect to CDRS
|
||||
if reflect.DeepEqual(cfg.SmGenericConfig.HaCdrs, cfg.SmGenericConfig.HaRater) {
|
||||
cdrsConn = raterConn
|
||||
} else if len(cfg.SmGenericConfig.HaCdrs) != 0 {
|
||||
for _, cdrsCfg := range cfg.SmGenericConfig.HaCdrs {
|
||||
if cdrsCfg.Server == utils.INTERNAL {
|
||||
resp := <-internalRaterChan
|
||||
cdrsConn = resp
|
||||
internalRaterChan <- resp
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", cdrsCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SM-Generic> Could not connect to CDRS via RPC: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
cdrsConn = &engine.RPCClientConnector{Client: client}
|
||||
}
|
||||
if len(cfg.SmGenericConfig.CDRsConns) != 0 {
|
||||
cdrsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.SmGenericConfig.CDRsConns, internalCDRSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SMGeneric> Could not connect to RAL: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
smg_econns := sessionmanager.NewSMGExternalConnections()
|
||||
sm := sessionmanager.NewSMGeneric(cfg, raterConn, cdrsConn, cfg.DefaultTimezone, smg_econns)
|
||||
sm := sessionmanager.NewSMGeneric(cfg, ralsConns, cdrsConn, cfg.DefaultTimezone, smg_econns)
|
||||
if err = sm.Connect(); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SM-Generic> error: %s!", err))
|
||||
utils.Logger.Err(fmt.Sprintf("<SMGeneric> error: %s!", err))
|
||||
}
|
||||
// Register RPC handler
|
||||
smgRpc := v1.NewSMGenericV1(sm)
|
||||
@@ -198,31 +170,24 @@ func startSmGeneric(internalSMGChan chan rpcclient.RpcClientConnection, internal
|
||||
|
||||
func startDiameterAgent(internalSMGChan, internalPubSubSChan chan rpcclient.RpcClientConnection, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS DiameterAgent service.")
|
||||
var smgConn, pubsubConn *rpcclient.RpcClient
|
||||
var err error
|
||||
if cfg.DiameterAgentCfg().SMGeneric == utils.INTERNAL {
|
||||
smgRpc := <-internalSMGChan
|
||||
internalSMGChan <- smgRpc
|
||||
smgConn, err = rpcclient.NewRpcClient("", "", 0, 0, rpcclient.INTERNAL_RPC, smgRpc)
|
||||
} else {
|
||||
smgConn, err = rpcclient.NewRpcClient("tcp", cfg.DiameterAgentCfg().SMGeneric, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
var smgConn, pubsubConn *rpcclient.RpcClientPool
|
||||
if len(cfg.DiameterAgentCfg().SMGenericConns) != 0 {
|
||||
smgConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.DiameterAgentCfg().SMGenericConns, internalSMGChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<DiameterAgent> Could not connect to SMG: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<DiameterAgent> Could not connect to SMG: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
if cfg.DiameterAgentCfg().PubSubS == utils.INTERNAL {
|
||||
pubSubRpc := <-internalPubSubSChan
|
||||
internalPubSubSChan <- pubSubRpc
|
||||
pubsubConn, err = rpcclient.NewRpcClient("", "", 0, 0, rpcclient.INTERNAL_RPC, pubSubRpc)
|
||||
} else if len(cfg.DiameterAgentCfg().PubSubS) != 0 {
|
||||
pubsubConn, err = rpcclient.NewRpcClient("tcp", cfg.DiameterAgentCfg().PubSubS, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
}
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<DiameterAgent> Could not connect to PubSubS: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
if len(cfg.DiameterAgentCfg().PubSubConns) != 0 {
|
||||
pubsubConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.DiameterAgentCfg().PubSubConns, internalPubSubSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<DiameterAgent> Could not connect to PubSubS: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
da, err := agents.NewDiameterAgent(cfg, smgConn, pubsubConn)
|
||||
if err != nil {
|
||||
@@ -236,146 +201,86 @@ func startDiameterAgent(internalSMGChan, internalPubSubSChan chan rpcclient.RpcC
|
||||
exitChan <- true
|
||||
}
|
||||
|
||||
func startSmFreeSWITCH(internalRaterChan chan *engine.Responder, cdrDb engine.CdrStorage, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS SM-FreeSWITCH service.")
|
||||
var raterConn, cdrsConn engine.Connector
|
||||
var client *rpcclient.RpcClient
|
||||
var err error
|
||||
// Connect to rater
|
||||
for _, raterCfg := range cfg.SmFsConfig.HaRater {
|
||||
if raterCfg.Server == utils.INTERNAL {
|
||||
resp := <-internalRaterChan
|
||||
raterConn = resp // Will overwrite here for the sake of keeping internally the new configuration format for ha connections
|
||||
internalRaterChan <- resp
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", raterCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil { //Connected so no need to reiterate
|
||||
utils.Logger.Crit(fmt.Sprintf("<SM-FreeSWITCH> Could not connect to rater via RPC: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
raterConn = &engine.RPCClientConnector{Client: client}
|
||||
func startSmFreeSWITCH(internalRaterChan, internalCDRSChan chan rpcclient.RpcClientConnection, cdrDb engine.CdrStorage, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS SMFreeSWITCH service.")
|
||||
var ralsConn, cdrsConn *rpcclient.RpcClientPool
|
||||
if len(cfg.SmFsConfig.RALsConns) != 0 {
|
||||
ralsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.SmFsConfig.RALsConns, internalRaterChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SMFreeSWITCH> Could not connect to RAL: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
// Connect to CDRS
|
||||
if reflect.DeepEqual(cfg.SmFsConfig.HaCdrs, cfg.SmFsConfig.HaRater) {
|
||||
cdrsConn = raterConn
|
||||
} else if len(cfg.SmFsConfig.HaCdrs) != 0 {
|
||||
for _, cdrsCfg := range cfg.SmFsConfig.HaCdrs {
|
||||
if cdrsCfg.Server == utils.INTERNAL {
|
||||
resp := <-internalRaterChan
|
||||
cdrsConn = resp
|
||||
internalRaterChan <- resp
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", cdrsCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SM-FreeSWITCH> Could not connect to CDRS via RPC: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
cdrsConn = &engine.RPCClientConnector{Client: client}
|
||||
}
|
||||
if len(cfg.SmFsConfig.CDRsConns) != 0 {
|
||||
cdrsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.SmFsConfig.CDRsConns, internalCDRSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SMFreeSWITCH> Could not connect to RAL: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
sm := sessionmanager.NewFSSessionManager(cfg.SmFsConfig, raterConn, cdrsConn, cfg.DefaultTimezone)
|
||||
sm := sessionmanager.NewFSSessionManager(cfg.SmFsConfig, ralsConn, cdrsConn, cfg.DefaultTimezone)
|
||||
smRpc.SMs = append(smRpc.SMs, sm)
|
||||
if err = sm.Connect(); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> error: %s!", err))
|
||||
utils.Logger.Err(fmt.Sprintf("<SMFreeSWITCH> error: %s!", err))
|
||||
}
|
||||
exitChan <- true
|
||||
}
|
||||
|
||||
func startSmKamailio(internalRaterChan chan *engine.Responder, cdrDb engine.CdrStorage, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS SM-Kamailio service.")
|
||||
var raterConn, cdrsConn engine.Connector
|
||||
var client *rpcclient.RpcClient
|
||||
var err error
|
||||
// Connect to rater
|
||||
for _, raterCfg := range cfg.SmKamConfig.HaRater {
|
||||
if raterCfg.Server == utils.INTERNAL {
|
||||
resp := <-internalRaterChan
|
||||
raterConn = resp // Will overwrite here for the sake of keeping internally the new configuration format for ha connections
|
||||
internalRaterChan <- resp
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", raterCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil { //Connected so no need to reiterate
|
||||
utils.Logger.Crit(fmt.Sprintf("<SM-Kamailio> Could not connect to rater via RPC: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
raterConn = &engine.RPCClientConnector{Client: client}
|
||||
func startSmKamailio(internalRaterChan, internalCDRSChan chan rpcclient.RpcClientConnection, cdrDb engine.CdrStorage, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS SMKamailio service.")
|
||||
var ralsConn, cdrsConn *rpcclient.RpcClientPool
|
||||
if len(cfg.SmKamConfig.RALsConns) != 0 {
|
||||
ralsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.SmKamConfig.RALsConns, internalRaterChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SMKamailio> Could not connect to RAL: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
// Connect to CDRS
|
||||
if reflect.DeepEqual(cfg.SmKamConfig.HaCdrs, cfg.SmKamConfig.HaRater) {
|
||||
cdrsConn = raterConn
|
||||
} else if len(cfg.SmKamConfig.HaCdrs) != 0 {
|
||||
for _, cdrsCfg := range cfg.SmKamConfig.HaCdrs {
|
||||
if cdrsCfg.Server == utils.INTERNAL {
|
||||
resp := <-internalRaterChan
|
||||
cdrsConn = resp
|
||||
internalRaterChan <- resp
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", cdrsCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SM-Kamailio> Could not connect to CDRS via RPC: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
cdrsConn = &engine.RPCClientConnector{Client: client}
|
||||
}
|
||||
if len(cfg.SmKamConfig.CDRsConns) != 0 {
|
||||
cdrsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.SmKamConfig.CDRsConns, internalCDRSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SMKamailio> Could not connect to RAL: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
sm, _ := sessionmanager.NewKamailioSessionManager(cfg.SmKamConfig, raterConn, cdrsConn, cfg.DefaultTimezone)
|
||||
sm, _ := sessionmanager.NewKamailioSessionManager(cfg.SmKamConfig, ralsConn, cdrsConn, cfg.DefaultTimezone)
|
||||
smRpc.SMs = append(smRpc.SMs, sm)
|
||||
if err = sm.Connect(); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SM-Kamailio> error: %s!", err))
|
||||
utils.Logger.Err(fmt.Sprintf("<SMKamailio> error: %s!", err))
|
||||
}
|
||||
exitChan <- true
|
||||
}
|
||||
|
||||
func startSmOpenSIPS(internalRaterChan chan *engine.Responder, cdrDb engine.CdrStorage, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS SM-OpenSIPS service.")
|
||||
var raterConn, cdrsConn engine.Connector
|
||||
var client *rpcclient.RpcClient
|
||||
var err error
|
||||
// Connect to rater
|
||||
for _, raterCfg := range cfg.SmOsipsConfig.HaRater {
|
||||
if raterCfg.Server == utils.INTERNAL {
|
||||
resp := <-internalRaterChan
|
||||
raterConn = resp // Will overwrite here for the sake of keeping internally the new configuration format for ha connections
|
||||
internalRaterChan <- resp
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", raterCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil { //Connected so no need to reiterate
|
||||
utils.Logger.Crit(fmt.Sprintf("<SM-OpenSIPS> Could not connect to rater via RPC: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
raterConn = &engine.RPCClientConnector{Client: client}
|
||||
func startSmOpenSIPS(internalRaterChan, internalCDRSChan chan rpcclient.RpcClientConnection, cdrDb engine.CdrStorage, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS SMOpenSIPS service.")
|
||||
var ralsConn, cdrsConn *rpcclient.RpcClientPool
|
||||
if len(cfg.SmOsipsConfig.RALsConns) != 0 {
|
||||
ralsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.SmOsipsConfig.RALsConns, internalRaterChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SMOpenSIPS> Could not connect to RALs: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
// Connect to CDRS
|
||||
if reflect.DeepEqual(cfg.SmOsipsConfig.HaCdrs, cfg.SmOsipsConfig.HaRater) {
|
||||
cdrsConn = raterConn
|
||||
} else if len(cfg.SmOsipsConfig.HaCdrs) != 0 {
|
||||
for _, cdrsCfg := range cfg.SmOsipsConfig.HaCdrs {
|
||||
if cdrsCfg.Server == utils.INTERNAL {
|
||||
resp := <-internalRaterChan
|
||||
cdrsConn = resp
|
||||
internalRaterChan <- resp
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", cdrsCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SM-OpenSIPS> Could not connect to CDRS via RPC: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
cdrsConn = &engine.RPCClientConnector{Client: client}
|
||||
}
|
||||
if len(cfg.SmOsipsConfig.CDRsConns) != 0 {
|
||||
cdrsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.SmOsipsConfig.CDRsConns, internalRaterChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<SMOpenSIPS> Could not connect to CDRs: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
sm, _ := sessionmanager.NewOSipsSessionManager(cfg.SmOsipsConfig, cfg.Reconnects, raterConn, cdrsConn, cfg.DefaultTimezone)
|
||||
sm, _ := sessionmanager.NewOSipsSessionManager(cfg.SmOsipsConfig, cfg.Reconnects, ralsConn, cdrsConn, cfg.DefaultTimezone)
|
||||
smRpc.SMs = append(smRpc.SMs, sm)
|
||||
if err := sm.Connect(); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SM-OpenSIPS> error: %s!", err))
|
||||
@@ -383,102 +288,60 @@ func startSmOpenSIPS(internalRaterChan chan *engine.Responder, cdrDb engine.CdrS
|
||||
exitChan <- true
|
||||
}
|
||||
|
||||
func startCDRS(internalCdrSChan chan *engine.CdrServer, logDb engine.LogStorage, cdrDb engine.CdrStorage,
|
||||
internalRaterChan chan *engine.Responder, internalPubSubSChan chan rpcclient.RpcClientConnection,
|
||||
internalUserSChan chan engine.UserService, internalAliaseSChan chan engine.AliasService,
|
||||
internalCdrStatSChan chan engine.StatsInterface, server *utils.Server, exitChan chan bool) {
|
||||
func startCDRS(internalCdrSChan chan rpcclient.RpcClientConnection, logDb engine.LogStorage, cdrDb engine.CdrStorage,
|
||||
internalRaterChan chan rpcclient.RpcClientConnection, internalPubSubSChan chan rpcclient.RpcClientConnection,
|
||||
internalUserSChan chan rpcclient.RpcClientConnection, internalAliaseSChan chan rpcclient.RpcClientConnection,
|
||||
internalCdrStatSChan chan rpcclient.RpcClientConnection, server *utils.Server, exitChan chan bool) {
|
||||
utils.Logger.Info("Starting CGRateS CDRS service.")
|
||||
var err error
|
||||
var client *rpcclient.RpcClient
|
||||
// Rater connection init
|
||||
var raterConn engine.Connector
|
||||
if cfg.CDRSRater == utils.INTERNAL {
|
||||
responder := <-internalRaterChan // Wait for rater to come up before start querying
|
||||
raterConn = responder
|
||||
internalRaterChan <- responder // Put back the connection since there might be other entities waiting for it
|
||||
} else if len(cfg.CDRSRater) != 0 {
|
||||
client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSRater, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
var ralConn, pubSubConn, usersConn, aliasesConn, statsConn *rpcclient.RpcClientPool
|
||||
if len(cfg.CDRSRaterConns) != 0 { // Conn pool towards RAL
|
||||
ralConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.CDRSRaterConns, internalRaterChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to rater: %s", err.Error()))
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to RAL: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
raterConn = &engine.RPCClientConnector{Client: client}
|
||||
}
|
||||
// Pubsub connection init
|
||||
var pubSubConn rpcclient.RpcClientConnection
|
||||
if cfg.CDRSPubSub == utils.INTERNAL {
|
||||
pubSubs := <-internalPubSubSChan
|
||||
pubSubConn = pubSubs
|
||||
internalPubSubSChan <- pubSubs
|
||||
} else if len(cfg.CDRSPubSub) != 0 {
|
||||
client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSPubSub, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if len(cfg.CDRSPubSubSConns) != 0 { // Pubsub connection init
|
||||
pubSubConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.CDRSPubSubSConns, internalPubSubSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to pubsub server: %s", err.Error()))
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to PubSubSystem: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
pubSubConn = client
|
||||
}
|
||||
// Users connection init
|
||||
var usersConn engine.UserService
|
||||
if cfg.CDRSUsers == utils.INTERNAL {
|
||||
userS := <-internalUserSChan
|
||||
usersConn = userS
|
||||
internalUserSChan <- userS
|
||||
} else if len(cfg.CDRSUsers) != 0 {
|
||||
if cfg.CDRSRater == cfg.CDRSUsers {
|
||||
usersConn = &engine.ProxyUserService{Client: client}
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSUsers, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to users server: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
usersConn = &engine.ProxyUserService{Client: client}
|
||||
if len(cfg.CDRSUserSConns) != 0 { // Users connection init
|
||||
usersConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.CDRSUserSConns, internalUserSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to UserS: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
// Aliases connection init
|
||||
var aliasesConn engine.AliasService
|
||||
if cfg.CDRSAliases == utils.INTERNAL {
|
||||
aliaseS := <-internalAliaseSChan
|
||||
aliasesConn = aliaseS
|
||||
internalAliaseSChan <- aliaseS
|
||||
} else if len(cfg.CDRSAliases) != 0 {
|
||||
if cfg.CDRSRater == cfg.CDRSAliases {
|
||||
aliasesConn = &engine.ProxyAliasService{Client: client}
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSAliases, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to aliases server: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
aliasesConn = &engine.ProxyAliasService{Client: client}
|
||||
}
|
||||
}
|
||||
// Stats connection init
|
||||
var statsConn engine.StatsInterface
|
||||
if cfg.CDRSStats == utils.INTERNAL {
|
||||
statS := <-internalCdrStatSChan
|
||||
statsConn = statS
|
||||
internalCdrStatSChan <- statS
|
||||
} else if len(cfg.CDRSStats) != 0 {
|
||||
if cfg.CDRSRater == cfg.CDRSStats {
|
||||
statsConn = &engine.ProxyStats{Client: client}
|
||||
} else {
|
||||
client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSStats, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to stats server: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
statsConn = &engine.ProxyStats{Client: client}
|
||||
if len(cfg.CDRSAliaseSConns) != 0 { // Aliases connection init
|
||||
aliasesConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.CDRSAliaseSConns, internalAliaseSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to AliaseS: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cdrServer, _ := engine.NewCdrServer(cfg, cdrDb, raterConn, pubSubConn, usersConn, aliasesConn, statsConn)
|
||||
if len(cfg.CDRSStatSConns) != 0 { // Stats connection init
|
||||
statsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.CDRSStatSConns, internalCdrStatSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to StatS: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
cdrServer, _ := engine.NewCdrServer(cfg, cdrDb, ralConn, pubSubConn, usersConn, aliasesConn, statsConn)
|
||||
cdrServer.SetTimeToLive(cfg.ResponseCacheTTL, nil)
|
||||
utils.Logger.Info("Registering CDRS HTTP Handlers.")
|
||||
cdrServer.RegisterHandlersToServer(server)
|
||||
utils.Logger.Info("Registering CDRS RPC service.")
|
||||
@@ -486,10 +349,8 @@ func startCDRS(internalCdrSChan chan *engine.CdrServer, logDb engine.LogStorage,
|
||||
server.RpcRegister(&cdrSrv)
|
||||
server.RpcRegister(&v2.CdrsV2{CdrsV1: cdrSrv})
|
||||
// Make the cdr server available for internal communication
|
||||
responder := <-internalRaterChan // Retrieve again the responder
|
||||
responder.CdrSrv = cdrServer // Attach connection to cdrServer in responder, so it can be used later
|
||||
internalRaterChan <- responder // Put back the connection for the rest of the system
|
||||
internalCdrSChan <- cdrServer // Signal that cdrS is operational
|
||||
server.RpcRegister(cdrServer) // register CdrServer for internal usage (TODO: refactor this)
|
||||
internalCdrSChan <- cdrServer // Signal that cdrS is operational
|
||||
}
|
||||
|
||||
func startScheduler(internalSchedulerChan chan *scheduler.Scheduler, cacheDoneChan chan struct{}, ratingDb engine.RatingStorage, exitChan chan bool) {
|
||||
@@ -506,20 +367,20 @@ func startScheduler(internalSchedulerChan chan *scheduler.Scheduler, cacheDoneCh
|
||||
exitChan <- true // Should not get out of loop though
|
||||
}
|
||||
|
||||
func startCdrStats(internalCdrStatSChan chan engine.StatsInterface, ratingDb engine.RatingStorage, accountDb engine.AccountingStorage, server *utils.Server) {
|
||||
func startCdrStats(internalCdrStatSChan chan rpcclient.RpcClientConnection, ratingDb engine.RatingStorage, accountDb engine.AccountingStorage, server *utils.Server) {
|
||||
cdrStats := engine.NewStats(ratingDb, accountDb, cfg.CDRStatsSaveInterval)
|
||||
server.RpcRegister(cdrStats)
|
||||
server.RpcRegister(&v1.CDRStatsV1{CdrStats: cdrStats}) // Public APIs
|
||||
internalCdrStatSChan <- cdrStats
|
||||
}
|
||||
|
||||
func startHistoryServer(internalHistorySChan chan history.Scribe, server *utils.Server, exitChan chan bool) {
|
||||
func startHistoryServer(internalHistorySChan chan rpcclient.RpcClientConnection, server *utils.Server, exitChan chan bool) {
|
||||
scribeServer, err := history.NewFileScribe(cfg.HistoryDir, cfg.HistorySaveInterval)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<HistoryServer> Could not start, error: %s", err.Error()))
|
||||
exitChan <- true
|
||||
}
|
||||
server.RpcRegisterName("ScribeV1", scribeServer)
|
||||
server.RpcRegisterName("HistoryV1", scribeServer)
|
||||
internalHistorySChan <- scribeServer
|
||||
}
|
||||
|
||||
@@ -530,7 +391,7 @@ func startPubSubServer(internalPubSubSChan chan rpcclient.RpcClientConnection, a
|
||||
}
|
||||
|
||||
// ToDo: Make sure we are caching before starting this one
|
||||
func startAliasesServer(internalAliaseSChan chan engine.AliasService, accountDb engine.AccountingStorage, server *utils.Server, exitChan chan bool) {
|
||||
func startAliasesServer(internalAliaseSChan chan rpcclient.RpcClientConnection, accountDb engine.AccountingStorage, server *utils.Server, exitChan chan bool) {
|
||||
aliasesServer := engine.NewAliasHandler(accountDb)
|
||||
server.RpcRegisterName("AliasesV1", aliasesServer)
|
||||
if err := accountDb.CacheAccountingPrefixes(utils.ALIASES_PREFIX); err != nil {
|
||||
@@ -541,7 +402,7 @@ func startAliasesServer(internalAliaseSChan chan engine.AliasService, accountDb
|
||||
internalAliaseSChan <- aliasesServer
|
||||
}
|
||||
|
||||
func startUsersServer(internalUserSChan chan engine.UserService, accountDb engine.AccountingStorage, server *utils.Server, exitChan chan bool) {
|
||||
func startUsersServer(internalUserSChan chan rpcclient.RpcClientConnection, accountDb engine.AccountingStorage, server *utils.Server, exitChan chan bool) {
|
||||
userServer, err := engine.NewUserMap(accountDb, cfg.UserServerIndexes)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<UsersService> Could not start, error: %s", err.Error()))
|
||||
@@ -552,13 +413,9 @@ func startUsersServer(internalUserSChan chan engine.UserService, accountDb engin
|
||||
internalUserSChan <- userServer
|
||||
}
|
||||
|
||||
func startRpc(server *utils.Server, internalRaterChan chan *engine.Responder,
|
||||
internalCdrSChan chan *engine.CdrServer,
|
||||
internalCdrStatSChan chan engine.StatsInterface,
|
||||
internalHistorySChan chan history.Scribe,
|
||||
internalPubSubSChan chan rpcclient.RpcClientConnection,
|
||||
internalUserSChan chan engine.UserService,
|
||||
internalAliaseSChan chan engine.AliasService) {
|
||||
func startRpc(server *utils.Server, internalRaterChan,
|
||||
internalCdrSChan, internalCdrStatSChan, internalHistorySChan, internalPubSubSChan, internalUserSChan,
|
||||
internalAliaseSChan chan rpcclient.RpcClientConnection) {
|
||||
select { // Any of the rpc methods will unlock listening to rpc requests
|
||||
case resp := <-internalRaterChan:
|
||||
internalRaterChan <- resp
|
||||
@@ -619,7 +476,7 @@ func main() {
|
||||
}
|
||||
config.SetCgrConfig(cfg) // Share the config object
|
||||
if *raterEnabled {
|
||||
cfg.RaterEnabled = *raterEnabled
|
||||
cfg.RALsEnabled = *raterEnabled
|
||||
}
|
||||
if *schedEnabled {
|
||||
cfg.SchedulerEnabled = *schedEnabled
|
||||
@@ -632,7 +489,7 @@ func main() {
|
||||
var logDb engine.LogStorage
|
||||
var loadDb engine.LoadStorage
|
||||
var cdrDb engine.CdrStorage
|
||||
if cfg.RaterEnabled || cfg.SchedulerEnabled || cfg.CDRStatsEnabled { // Only connect to dataDb if necessary
|
||||
if cfg.RALsEnabled || cfg.SchedulerEnabled || cfg.CDRStatsEnabled { // Only connect to dataDb if necessary
|
||||
ratingDb, err = engine.ConfigureRatingStorage(cfg.TpDbType, cfg.TpDbHost, cfg.TpDbPort,
|
||||
cfg.TpDbName, cfg.TpDbUser, cfg.TpDbPass, cfg.DBDataEncoding)
|
||||
if err != nil { // Cannot configure getter database, show stopper
|
||||
@@ -642,7 +499,7 @@ func main() {
|
||||
defer ratingDb.Close()
|
||||
engine.SetRatingStorage(ratingDb)
|
||||
}
|
||||
if cfg.RaterEnabled || cfg.CDRStatsEnabled || cfg.PubSubServerEnabled || cfg.AliasesServerEnabled || cfg.UserServerEnabled {
|
||||
if cfg.RALsEnabled || cfg.CDRStatsEnabled || cfg.PubSubServerEnabled || cfg.AliasesServerEnabled || cfg.UserServerEnabled {
|
||||
accountDb, err = engine.ConfigureAccountingStorage(cfg.DataDbType, cfg.DataDbHost, cfg.DataDbPort,
|
||||
cfg.DataDbName, cfg.DataDbUser, cfg.DataDbPass, cfg.DBDataEncoding)
|
||||
if err != nil { // Cannot configure getter database, show stopper
|
||||
@@ -651,8 +508,12 @@ func main() {
|
||||
}
|
||||
defer accountDb.Close()
|
||||
engine.SetAccountingStorage(accountDb)
|
||||
if err := engine.CheckVersion(); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
if cfg.RaterEnabled || cfg.CDRSEnabled || cfg.SchedulerEnabled { // Only connect to storDb if necessary
|
||||
if cfg.RALsEnabled || cfg.CDRSEnabled || cfg.SchedulerEnabled { // Only connect to storDb if necessary
|
||||
logDb, err = engine.ConfigureLogStorage(cfg.StorDBType, cfg.StorDBHost, cfg.StorDBPort,
|
||||
cfg.StorDBName, cfg.StorDBUser, cfg.StorDBPass, cfg.DBDataEncoding, cfg.StorDBMaxOpenConns, cfg.StorDBMaxIdleConns, cfg.StorDBCDRSIndexes)
|
||||
if err != nil { // Cannot configure logger database, show stopper
|
||||
@@ -668,6 +529,8 @@ func main() {
|
||||
}
|
||||
|
||||
engine.SetRoundingDecimals(cfg.RoundingDecimals)
|
||||
engine.SetRpSubjectPrefixMatching(cfg.RpSubjectPrefixMatching)
|
||||
engine.SetLcrSubjectPrefixMatching(cfg.LcrSubjectPrefixMatching)
|
||||
stopHandled := false
|
||||
|
||||
// Rpc/http server
|
||||
@@ -678,15 +541,15 @@ func main() {
|
||||
|
||||
// Define internal connections via channels
|
||||
internalBalancerChan := make(chan *balancer2go.Balancer, 1)
|
||||
internalRaterChan := make(chan *engine.Responder, 1)
|
||||
internalRaterChan := make(chan rpcclient.RpcClientConnection, 1)
|
||||
cacheDoneChan := make(chan struct{}, 1)
|
||||
internalSchedulerChan := make(chan *scheduler.Scheduler, 1)
|
||||
internalCdrSChan := make(chan *engine.CdrServer, 1)
|
||||
internalCdrStatSChan := make(chan engine.StatsInterface, 1)
|
||||
internalHistorySChan := make(chan history.Scribe, 1)
|
||||
internalCdrSChan := make(chan rpcclient.RpcClientConnection, 1)
|
||||
internalCdrStatSChan := make(chan rpcclient.RpcClientConnection, 1)
|
||||
internalHistorySChan := make(chan rpcclient.RpcClientConnection, 1)
|
||||
internalPubSubSChan := make(chan rpcclient.RpcClientConnection, 1)
|
||||
internalUserSChan := make(chan engine.UserService, 1)
|
||||
internalAliaseSChan := make(chan engine.AliasService, 1)
|
||||
internalUserSChan := make(chan rpcclient.RpcClientConnection, 1)
|
||||
internalAliaseSChan := make(chan rpcclient.RpcClientConnection, 1)
|
||||
internalSMGChan := make(chan rpcclient.RpcClientConnection, 1)
|
||||
// Start balancer service
|
||||
if cfg.BalancerEnabled {
|
||||
@@ -694,7 +557,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Start rater service
|
||||
if cfg.RaterEnabled {
|
||||
if cfg.RALsEnabled {
|
||||
go startRater(internalRaterChan, cacheDoneChan, internalBalancerChan, internalSchedulerChan, internalCdrStatSChan, internalHistorySChan, internalPubSubSChan, internalUserSChan, internalAliaseSChan,
|
||||
server, ratingDb, accountDb, loadDb, cdrDb, logDb, &stopHandled, exitChan)
|
||||
}
|
||||
@@ -719,23 +582,23 @@ func main() {
|
||||
|
||||
// Start SM-Generic
|
||||
if cfg.SmGenericConfig.Enabled {
|
||||
go startSmGeneric(internalSMGChan, internalRaterChan, server, exitChan)
|
||||
go startSmGeneric(internalSMGChan, internalRaterChan, internalCdrSChan, server, exitChan)
|
||||
}
|
||||
// Start SM-FreeSWITCH
|
||||
if cfg.SmFsConfig.Enabled {
|
||||
go startSmFreeSWITCH(internalRaterChan, cdrDb, exitChan)
|
||||
go startSmFreeSWITCH(internalRaterChan, internalCdrSChan, cdrDb, exitChan)
|
||||
// close all sessions on shutdown
|
||||
go shutdownSessionmanagerSingnalHandler(exitChan)
|
||||
}
|
||||
|
||||
// Start SM-Kamailio
|
||||
if cfg.SmKamConfig.Enabled {
|
||||
go startSmKamailio(internalRaterChan, cdrDb, exitChan)
|
||||
go startSmKamailio(internalRaterChan, internalCdrSChan, cdrDb, exitChan)
|
||||
}
|
||||
|
||||
// Start SM-OpenSIPS
|
||||
if cfg.SmOsipsConfig.Enabled {
|
||||
go startSmOpenSIPS(internalRaterChan, cdrDb, exitChan)
|
||||
go startSmOpenSIPS(internalRaterChan, internalCdrSChan, cdrDb, exitChan)
|
||||
}
|
||||
|
||||
// Register session manager service // FixMe: make sure this is thread safe
|
||||
|
||||
@@ -40,9 +40,10 @@ func startBalancer(internalBalancerChan chan *balancer2go.Balancer, stopHandled
|
||||
}
|
||||
|
||||
// Starts rater and reports on chan
|
||||
func startRater(internalRaterChan chan *engine.Responder, cacheDoneChan chan struct{}, internalBalancerChan chan *balancer2go.Balancer, internalSchedulerChan chan *scheduler.Scheduler,
|
||||
internalCdrStatSChan chan engine.StatsInterface, internalHistorySChan chan history.Scribe,
|
||||
internalPubSubSChan chan rpcclient.RpcClientConnection, internalUserSChan chan engine.UserService, internalAliaseSChan chan engine.AliasService,
|
||||
|
||||
func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneChan chan struct{}, internalBalancerChan chan *balancer2go.Balancer, internalSchedulerChan chan *scheduler.Scheduler,
|
||||
internalCdrStatSChan chan rpcclient.RpcClientConnection, internalHistorySChan chan rpcclient.RpcClientConnection,
|
||||
internalPubSubSChan chan rpcclient.RpcClientConnection, internalUserSChan chan rpcclient.RpcClientConnection, internalAliaseSChan chan rpcclient.RpcClientConnection,
|
||||
server *utils.Server,
|
||||
ratingDb engine.RatingStorage, accountDb engine.AccountingStorage, loadDb engine.LoadStorage, cdrDb engine.CdrStorage, logDb engine.LogStorage,
|
||||
stopHandled *bool, exitChan chan bool) {
|
||||
@@ -84,15 +85,13 @@ func startRater(internalRaterChan chan *engine.Responder, cacheDoneChan chan str
|
||||
|
||||
}()
|
||||
}
|
||||
|
||||
// Connection to balancer
|
||||
var bal *balancer2go.Balancer
|
||||
if cfg.RaterBalancer != "" {
|
||||
if cfg.RALsBalancer != "" { // Connection to balancer
|
||||
balTaskChan := make(chan struct{})
|
||||
waitTasks = append(waitTasks, balTaskChan)
|
||||
go func() {
|
||||
defer close(balTaskChan)
|
||||
if cfg.RaterBalancer == utils.INTERNAL {
|
||||
if cfg.RALsBalancer == utils.MetaInternal {
|
||||
select {
|
||||
case bal = <-internalBalancerChan:
|
||||
internalBalancerChan <- bal // Put it back if someone else is interested about
|
||||
@@ -108,144 +107,117 @@ func startRater(internalRaterChan chan *engine.Responder, cacheDoneChan chan str
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Connection to CDRStats
|
||||
var cdrStats engine.StatsInterface
|
||||
if cfg.RaterCdrStats != "" {
|
||||
var cdrStats *rpcclient.RpcClientPool
|
||||
if len(cfg.RALsCDRStatSConns) != 0 { // Connections to CDRStats
|
||||
cdrstatTaskChan := make(chan struct{})
|
||||
waitTasks = append(waitTasks, cdrstatTaskChan)
|
||||
go func() {
|
||||
defer close(cdrstatTaskChan)
|
||||
if cfg.RaterCdrStats == utils.INTERNAL {
|
||||
select {
|
||||
case cdrStats = <-internalCdrStatSChan:
|
||||
internalCdrStatSChan <- cdrStats
|
||||
case <-time.After(cfg.InternalTtl):
|
||||
utils.Logger.Crit("<Rater>: Internal cdrstats connection timeout.")
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
} else if cdrStats, err = engine.NewProxyStats(cfg.RaterCdrStats, cfg.ConnectAttempts, -1); err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect to cdrstats, error: %s", err.Error()))
|
||||
cdrStats, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.RALsCDRStatSConns, internalCdrStatSChan, cfg.InternalTtl)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect to CDRStatS, error: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Connection to HistoryS
|
||||
if cfg.RaterHistoryServer != "" {
|
||||
if len(cfg.RALsHistorySConns) != 0 { // Connection to HistoryS,
|
||||
histTaskChan := make(chan struct{})
|
||||
waitTasks = append(waitTasks, histTaskChan)
|
||||
go func() {
|
||||
defer close(histTaskChan)
|
||||
var scribeServer history.Scribe
|
||||
if cfg.RaterHistoryServer == utils.INTERNAL {
|
||||
select {
|
||||
case scribeServer = <-internalHistorySChan:
|
||||
internalHistorySChan <- scribeServer
|
||||
case <-time.After(cfg.InternalTtl):
|
||||
utils.Logger.Crit("<Rater>: Internal historys connection timeout.")
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
} else if scribeServer, err = history.NewProxyScribe(cfg.RaterHistoryServer, cfg.ConnectAttempts, -1); err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect historys, error: %s", err.Error()))
|
||||
if historySConns, err := engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.RALsHistorySConns, internalHistorySChan, cfg.InternalTtl); err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect HistoryS, error: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
} else {
|
||||
engine.SetHistoryScribe(historySConns)
|
||||
}
|
||||
engine.SetHistoryScribe(scribeServer) // ToDo: replace package sharing with connection based one
|
||||
}()
|
||||
}
|
||||
|
||||
// Connection to pubsubs
|
||||
if cfg.RaterPubSubServer != "" {
|
||||
if len(cfg.RALsPubSubSConns) != 0 { // Connection to pubsubs
|
||||
pubsubTaskChan := make(chan struct{})
|
||||
waitTasks = append(waitTasks, pubsubTaskChan)
|
||||
go func() {
|
||||
defer close(pubsubTaskChan)
|
||||
var pubSubServer rpcclient.RpcClientConnection
|
||||
if cfg.RaterPubSubServer == utils.INTERNAL {
|
||||
select {
|
||||
case pubSubServer = <-internalPubSubSChan:
|
||||
internalPubSubSChan <- pubSubServer
|
||||
case <-time.After(cfg.InternalTtl):
|
||||
utils.Logger.Crit("<Rater>: Internal pubsub connection timeout.")
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
} else if pubSubServer, err = rpcclient.NewRpcClient("tcp", cfg.RaterPubSubServer, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil); err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect to pubsubs: %s", err.Error()))
|
||||
if pubSubSConns, err := engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.RALsPubSubSConns, internalPubSubSChan, cfg.InternalTtl); err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect to PubSubS: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
} else {
|
||||
engine.SetPubSub(pubSubSConns)
|
||||
}
|
||||
engine.SetPubSub(pubSubServer) // ToDo: replace package sharing with connection based one
|
||||
}()
|
||||
}
|
||||
|
||||
// Connection to AliasService
|
||||
if cfg.RaterAliasesServer != "" {
|
||||
if len(cfg.RALsAliasSConns) != 0 { // Connection to AliasService
|
||||
aliasesTaskChan := make(chan struct{})
|
||||
waitTasks = append(waitTasks, aliasesTaskChan)
|
||||
go func() {
|
||||
defer close(aliasesTaskChan)
|
||||
var aliasesServer engine.AliasService
|
||||
if cfg.RaterAliasesServer == utils.INTERNAL {
|
||||
select {
|
||||
case aliasesServer = <-internalAliaseSChan:
|
||||
internalAliaseSChan <- aliasesServer
|
||||
case <-time.After(cfg.InternalTtl):
|
||||
utils.Logger.Crit("<Rater>: Internal aliases connection timeout.")
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
} else if aliasesServer, err = engine.NewProxyAliasService(cfg.RaterAliasesServer, cfg.ConnectAttempts, -1); err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect to aliases, error: %s", err.Error()))
|
||||
if aliaseSCons, err := engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.RALsAliasSConns, internalAliaseSChan, cfg.InternalTtl); err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect to AliaseS, error: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
} else {
|
||||
engine.SetAliasService(aliaseSCons)
|
||||
}
|
||||
engine.SetAliasService(aliasesServer) // ToDo: replace package sharing with connection based one
|
||||
}()
|
||||
}
|
||||
|
||||
// Connection to UserService
|
||||
var userServer engine.UserService
|
||||
if cfg.RaterUserServer != "" {
|
||||
var usersConns rpcclient.RpcClientConnection
|
||||
if len(cfg.RALsUserSConns) != 0 { // Connection to UserService
|
||||
usersTaskChan := make(chan struct{})
|
||||
waitTasks = append(waitTasks, usersTaskChan)
|
||||
go func() {
|
||||
defer close(usersTaskChan)
|
||||
if cfg.RaterUserServer == utils.INTERNAL {
|
||||
select {
|
||||
case userServer = <-internalUserSChan:
|
||||
internalUserSChan <- userServer
|
||||
case <-time.After(cfg.InternalTtl):
|
||||
utils.Logger.Crit("<Rater>: Internal users connection timeout.")
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
} else if userServer, err = engine.NewProxyUserService(cfg.RaterUserServer, cfg.ConnectAttempts, -1); err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect users, error: %s", err.Error()))
|
||||
if usersConns, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB,
|
||||
cfg.RALsUserSConns, internalUserSChan, cfg.InternalTtl); err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect UserS, error: %s", err.Error()))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
engine.SetUserService(userServer)
|
||||
engine.SetUserService(usersConns)
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait for all connections to complete before going further
|
||||
for _, chn := range waitTasks {
|
||||
<-chn
|
||||
}
|
||||
|
||||
responder := &engine.Responder{Bal: bal, ExitChan: exitChan, Stats: cdrStats}
|
||||
responder := &engine.Responder{Bal: bal, ExitChan: exitChan}
|
||||
responder.SetTimeToLive(cfg.ResponseCacheTTL, nil)
|
||||
apierRpcV1 := &v1.ApierV1{StorDb: loadDb, RatingDb: ratingDb, AccountDb: accountDb, CdrDb: cdrDb, LogDb: logDb, Sched: sched,
|
||||
Config: cfg, Responder: responder, CdrStatsSrv: cdrStats, Users: userServer}
|
||||
Config: cfg, Responder: responder}
|
||||
if cdrStats != nil { // ToDo: Fix here properly the init of stats
|
||||
responder.Stats = cdrStats
|
||||
apierRpcV1.CdrStatsSrv = cdrStats
|
||||
}
|
||||
if usersConns != nil {
|
||||
apierRpcV1.Users = usersConns
|
||||
}
|
||||
apierRpcV2 := &v2.ApierV2{
|
||||
ApierV1: *apierRpcV1}
|
||||
|
||||
// internalSchedulerChan shared here
|
||||
server.RpcRegister(responder)
|
||||
server.RpcRegister(apierRpcV1)
|
||||
server.RpcRegister(apierRpcV2)
|
||||
|
||||
utils.RegisterRpcParams("", &engine.Stats{})
|
||||
utils.RegisterRpcParams("", &v1.CDRStatsV1{})
|
||||
utils.RegisterRpcParams("ScribeV1", &history.FileScribe{})
|
||||
utils.RegisterRpcParams("PubSubV1", &engine.PubSub{})
|
||||
utils.RegisterRpcParams("AliasesV1", &engine.AliasHandler{})
|
||||
utils.RegisterRpcParams("UsersV1", &engine.UserMap{})
|
||||
utils.RegisterRpcParams("", &v1.CdrsV1{})
|
||||
utils.RegisterRpcParams("", &v2.CdrsV2{})
|
||||
utils.RegisterRpcParams("", &v1.SessionManagerV1{})
|
||||
utils.RegisterRpcParams("", &v1.SMGenericV1{})
|
||||
utils.RegisterRpcParams("", responder)
|
||||
utils.RegisterRpcParams("", apierRpcV1)
|
||||
utils.RegisterRpcParams("", apierRpcV2)
|
||||
utils.GetRpcParams("")
|
||||
internalRaterChan <- responder // Rater done
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/scheduler"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/rpcclient"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -43,7 +44,7 @@ func stopBalancerSignalHandler(bal *balancer2go.Balancer, exitChan chan bool) {
|
||||
exitChan <- true
|
||||
}
|
||||
|
||||
func generalSignalHandler(internalCdrStatSChan chan engine.StatsInterface, exitChan chan bool) {
|
||||
func generalSignalHandler(internalCdrStatSChan chan rpcclient.RpcClientConnection, exitChan chan bool) {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)
|
||||
|
||||
@@ -52,7 +53,7 @@ func generalSignalHandler(internalCdrStatSChan chan engine.StatsInterface, exitC
|
||||
var dummyInt int
|
||||
select {
|
||||
case cdrStats := <-internalCdrStatSChan:
|
||||
cdrStats.Stop(dummyInt, &dummyInt)
|
||||
cdrStats.Call("CDRStatsV1.Stop", dummyInt, &dummyInt)
|
||||
default:
|
||||
}
|
||||
|
||||
@@ -62,7 +63,7 @@ func generalSignalHandler(internalCdrStatSChan chan engine.StatsInterface, exitC
|
||||
/*
|
||||
Listens for the SIGTERM, SIGINT, SIGQUIT system signals and gracefuly unregister from balancer and closes the storage before exiting.
|
||||
*/
|
||||
func stopRaterSignalHandler(internalCdrStatSChan chan engine.StatsInterface, exitChan chan bool) {
|
||||
func stopRaterSignalHandler(internalCdrStatSChan chan rpcclient.RpcClientConnection, exitChan chan bool) {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)
|
||||
sig := <-c
|
||||
@@ -72,7 +73,7 @@ func stopRaterSignalHandler(internalCdrStatSChan chan engine.StatsInterface, exi
|
||||
var dummyInt int
|
||||
select {
|
||||
case cdrStats := <-internalCdrStatSChan:
|
||||
cdrStats.Stop(dummyInt, &dummyInt)
|
||||
cdrStats.Call("CDRStatsV1.Stop", dummyInt, &dummyInt)
|
||||
default:
|
||||
}
|
||||
exitChan <- true
|
||||
@@ -82,14 +83,14 @@ func stopRaterSignalHandler(internalCdrStatSChan chan engine.StatsInterface, exi
|
||||
Connects to the balancer and calls unregister RPC method.
|
||||
*/
|
||||
func unregisterFromBalancer(exitChan chan bool) {
|
||||
client, err := rpc.Dial("tcp", cfg.RaterBalancer)
|
||||
client, err := rpc.Dial("tcp", cfg.RALsBalancer)
|
||||
if err != nil {
|
||||
utils.Logger.Crit("Cannot contact the balancer!")
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
var reply int
|
||||
utils.Logger.Info(fmt.Sprintf("Unregistering from balancer %s", cfg.RaterBalancer))
|
||||
utils.Logger.Info(fmt.Sprintf("Unregistering from balancer %s", cfg.RALsBalancer))
|
||||
client.Call("Responder.UnRegisterRater", cfg.RPCGOBListen, &reply)
|
||||
if err := client.Close(); err != nil {
|
||||
utils.Logger.Crit("Could not close balancer unregistration!")
|
||||
@@ -101,14 +102,14 @@ func unregisterFromBalancer(exitChan chan bool) {
|
||||
Connects to the balancer and rehisters the engine to the server.
|
||||
*/
|
||||
func registerToBalancer(exitChan chan bool) {
|
||||
client, err := rpc.Dial("tcp", cfg.RaterBalancer)
|
||||
client, err := rpc.Dial("tcp", cfg.RALsBalancer)
|
||||
if err != nil {
|
||||
utils.Logger.Crit(fmt.Sprintf("Cannot contact the balancer: %v", err))
|
||||
exitChan <- true
|
||||
return
|
||||
}
|
||||
var reply int
|
||||
utils.Logger.Info(fmt.Sprintf("Registering to balancer %s", cfg.RaterBalancer))
|
||||
utils.Logger.Info(fmt.Sprintf("Registering to balancer %s", cfg.RALsBalancer))
|
||||
client.Call("Responder.RegisterRater", cfg.RPCGOBListen, &reply)
|
||||
if err := client.Close(); err != nil {
|
||||
utils.Logger.Crit("Could not close balancer registration!")
|
||||
|
||||
@@ -29,8 +29,8 @@ import (
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/history"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/rpcclient"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -92,77 +92,107 @@ func main() {
|
||||
var rater, cdrstats, users *rpc.Client
|
||||
var loader engine.LoadReader
|
||||
if *migrateRC8 != "" {
|
||||
var db_nb int
|
||||
db_nb, err = strconv.Atoi(*datadb_name)
|
||||
if err != nil {
|
||||
log.Print("Redis db name must be an integer!")
|
||||
return
|
||||
}
|
||||
host := *datadb_host
|
||||
if *datadb_port != "" {
|
||||
host += ":" + *datadb_port
|
||||
}
|
||||
migratorRC8acc, err := NewMigratorRC8(host, db_nb, *datadb_pass, *dbdata_encoding)
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "acc") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8acc.migrateAccounts(); err != nil {
|
||||
if *datadb_type == "redis" && *tpdb_type == "redis" {
|
||||
var db_nb int
|
||||
db_nb, err = strconv.Atoi(*datadb_name)
|
||||
if err != nil {
|
||||
log.Print("Redis db name must be an integer!")
|
||||
return
|
||||
}
|
||||
host := *datadb_host
|
||||
if *datadb_port != "" {
|
||||
host += ":" + *datadb_port
|
||||
}
|
||||
migratorRC8acc, err := NewMigratorRC8(host, db_nb, *datadb_pass, *dbdata_encoding)
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "acc") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8acc.migrateAccounts(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
db_nb, err = strconv.Atoi(*tpdb_name)
|
||||
if err != nil {
|
||||
log.Print("Redis db name must be an integer!")
|
||||
return
|
||||
}
|
||||
host = *tpdb_host
|
||||
if *tpdb_port != "" {
|
||||
host += ":" + *tpdb_port
|
||||
}
|
||||
migratorRC8rat, err := NewMigratorRC8(host, db_nb, *tpdb_pass, *dbdata_encoding)
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "atr") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateActionTriggers(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "act") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateActions(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "dcs") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateDerivedChargers(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "apl") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateActionPlans(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "shg") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateSharedGroups(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "int") {
|
||||
if err := migratorRC8acc.migrateAccountsInt(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
if err := migratorRC8rat.migrateActionTriggersInt(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
if err := migratorRC8rat.migrateActionsInt(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "vf") {
|
||||
if err := migratorRC8rat.migrateActionsInt2(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
if err := migratorRC8acc.writeVersion(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
} else if *datadb_type == "mongo" && *tpdb_type == "mongo" {
|
||||
mongoMigratorAcc, err := NewMongoMigrator(*datadb_host, *datadb_port, *datadb_name, *datadb_user, *datadb_pass)
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
mongoMigratorRat, err := NewMongoMigrator(*tpdb_host, *tpdb_port, *tpdb_name, *tpdb_user, *tpdb_pass)
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "vf") {
|
||||
if err := mongoMigratorRat.migrateActions(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
if err := mongoMigratorAcc.writeVersion(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db_nb, err = strconv.Atoi(*tpdb_name)
|
||||
if err != nil {
|
||||
log.Print("Redis db name must be an integer!")
|
||||
return
|
||||
}
|
||||
host = *tpdb_host
|
||||
if *tpdb_port != "" {
|
||||
host += ":" + *tpdb_port
|
||||
}
|
||||
migratorRC8rat, err := NewMigratorRC8(host, db_nb, *tpdb_pass, *dbdata_encoding)
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "atr") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateActionTriggers(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "act") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateActions(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "dcs") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateDerivedChargers(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "apl") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateActionPlans(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "shg") || strings.Contains(*migrateRC8, "*all") {
|
||||
if err := migratorRC8rat.migrateSharedGroups(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
if strings.Contains(*migrateRC8, "int") {
|
||||
if err := migratorRC8acc.migrateAccountsInt(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
if err := migratorRC8rat.migrateActionTriggersInt(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
if err := migratorRC8rat.migrateActionsInt(); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
log.Print("Done!")
|
||||
return
|
||||
}
|
||||
@@ -257,7 +287,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
if *historyServer != "" { // Init scribeAgent so we can store the differences
|
||||
if scribeAgent, err := history.NewProxyScribe(*historyServer, 3, 3); err != nil {
|
||||
if scribeAgent, err := rpcclient.NewRpcClient("tcp", *historyServer, 3, 3, utils.GOB, nil); err != nil {
|
||||
log.Fatalf("Could not connect to history server, error: %s. Make sure you have properly configured it via -history_server flag.", err.Error())
|
||||
return
|
||||
} else {
|
||||
|
||||
97
cmd/cgr-loader/migrator_mongo.go
Normal file
97
cmd/cgr-loader/migrator_mongo.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"gopkg.in/mgo.v2"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
type MongoMigrator struct {
|
||||
session *mgo.Session
|
||||
db *mgo.Database
|
||||
}
|
||||
|
||||
func NewMongoMigrator(host, port, db, user, pass string) (*MongoMigrator, error) {
|
||||
address := fmt.Sprintf("%s:%s", host, port)
|
||||
if user != "" && pass != "" {
|
||||
address = fmt.Sprintf("%s:%s@%s", user, pass, address)
|
||||
}
|
||||
session, err := mgo.Dial(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ndb := session.DB(db)
|
||||
return &MongoMigrator{session: session, db: ndb}, nil
|
||||
}
|
||||
|
||||
func (mig MongoMigrator) migrateActions() error {
|
||||
newAcsMap := make(map[string]engine.Actions)
|
||||
iter := mig.db.C("actions").Find(nil).Iter()
|
||||
var oldAcs struct {
|
||||
Key string
|
||||
Value Actions2
|
||||
}
|
||||
for iter.Next(&oldAcs) {
|
||||
log.Printf("Migrating action: %s...", oldAcs.Key)
|
||||
newAcs := make(engine.Actions, len(oldAcs.Value))
|
||||
for index, oldAc := range oldAcs.Value {
|
||||
a := &engine.Action{
|
||||
Id: oldAc.Id,
|
||||
ActionType: oldAc.ActionType,
|
||||
ExtraParameters: oldAc.ExtraParameters,
|
||||
ExpirationString: oldAc.ExpirationString,
|
||||
Filter: oldAc.Filter,
|
||||
Weight: oldAc.Weight,
|
||||
Balance: &engine.BalanceFilter{
|
||||
Uuid: oldAc.Balance.Uuid,
|
||||
ID: oldAc.Balance.ID,
|
||||
Type: oldAc.Balance.Type,
|
||||
Directions: oldAc.Balance.Directions,
|
||||
ExpirationDate: oldAc.Balance.ExpirationDate,
|
||||
Weight: oldAc.Balance.Weight,
|
||||
DestinationIDs: oldAc.Balance.DestinationIDs,
|
||||
RatingSubject: oldAc.Balance.RatingSubject,
|
||||
Categories: oldAc.Balance.Categories,
|
||||
SharedGroups: oldAc.Balance.SharedGroups,
|
||||
TimingIDs: oldAc.Balance.TimingIDs,
|
||||
Timings: oldAc.Balance.Timings,
|
||||
Disabled: oldAc.Balance.Disabled,
|
||||
Factor: oldAc.Balance.Factor,
|
||||
Blocker: oldAc.Balance.Blocker,
|
||||
},
|
||||
}
|
||||
if oldAc.Balance.Value != nil {
|
||||
a.Balance.Value = &utils.ValueFormula{Static: *oldAc.Balance.Value}
|
||||
}
|
||||
newAcs[index] = a
|
||||
}
|
||||
newAcsMap[oldAcs.Key] = newAcs
|
||||
}
|
||||
if err := iter.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write data back
|
||||
for key, acs := range newAcsMap {
|
||||
if _, err := mig.db.C("actions").Upsert(bson.M{"key": key}, &struct {
|
||||
Key string
|
||||
Value engine.Actions
|
||||
}{Key: key, Value: acs}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mig MongoMigrator) writeVersion() error {
|
||||
_, err := mig.db.C("versions").Upsert(bson.M{"key": utils.VERSION_PREFIX + "struct"}, &struct {
|
||||
Key string
|
||||
Value *engine.StructVersion
|
||||
}{utils.VERSION_PREFIX + "struct", engine.CurrentVersion})
|
||||
return err
|
||||
}
|
||||
@@ -482,7 +482,7 @@ func (mig MigratorRC8) migrateActions() error {
|
||||
bf.Type = utils.StringPointer(oldAc.BalanceType)
|
||||
}
|
||||
if oldAc.Balance.Value != 0 {
|
||||
bf.Value = utils.Float64Pointer(oldAc.Balance.Value)
|
||||
bf.Value = &utils.ValueFormula{Static: oldAc.Balance.Value}
|
||||
}
|
||||
if oldAc.Balance.RatingSubject != "" {
|
||||
bf.RatingSubject = utils.StringPointer(oldAc.Balance.RatingSubject)
|
||||
@@ -669,3 +669,11 @@ func (mig MigratorRC8) migrateSharedGroups() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mig MigratorRC8) writeVersion() error {
|
||||
result, err := mig.ms.Marshal(engine.CurrentVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return mig.db.Cmd("SET", utils.VERSION_PREFIX+"struct", result).Err
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ func (mig MigratorRC8) migrateActionsInt() error {
|
||||
bf.Type = utils.StringPointer(oldAc.BalanceType)
|
||||
}
|
||||
if oldAc.Balance.Value != 0 {
|
||||
bf.Value = utils.Float64Pointer(oldAc.Balance.Value)
|
||||
bf.Value = &utils.ValueFormula{Static: oldAc.Balance.Value}
|
||||
}
|
||||
if oldAc.Balance.RatingSubject != "" {
|
||||
bf.RatingSubject = utils.StringPointer(oldAc.Balance.RatingSubject)
|
||||
|
||||
102
cmd/cgr-loader/migrator_rc8int2.go
Normal file
102
cmd/cgr-loader/migrator_rc8int2.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
type BalanceFilter2 struct {
|
||||
Uuid *string
|
||||
ID *string
|
||||
Type *string
|
||||
Value *float64
|
||||
Directions *utils.StringMap
|
||||
ExpirationDate *time.Time
|
||||
Weight *float64
|
||||
DestinationIDs *utils.StringMap
|
||||
RatingSubject *string
|
||||
Categories *utils.StringMap
|
||||
SharedGroups *utils.StringMap
|
||||
TimingIDs *utils.StringMap
|
||||
Timings []*engine.RITiming
|
||||
Disabled *bool
|
||||
Factor *engine.ValueFactor
|
||||
Blocker *bool
|
||||
}
|
||||
|
||||
type Action2 struct {
|
||||
Id string
|
||||
ActionType string
|
||||
ExtraParameters string
|
||||
Filter string
|
||||
ExpirationString string // must stay as string because it can have relative values like 1month
|
||||
Weight float64
|
||||
Balance *BalanceFilter2
|
||||
}
|
||||
|
||||
type Actions2 []*Action2
|
||||
|
||||
func (mig MigratorRC8) migrateActionsInt2() error {
|
||||
keys, err := mig.db.Cmd("KEYS", utils.ACTION_PREFIX+"*").List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newAcsMap := make(map[string]engine.Actions, len(keys))
|
||||
for _, key := range keys {
|
||||
log.Printf("Migrating action: %s...", key)
|
||||
var oldAcs Actions2
|
||||
var values []byte
|
||||
if values, err = mig.db.Cmd("GET", key).Bytes(); err == nil {
|
||||
if err := mig.ms.Unmarshal(values, &oldAcs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
newAcs := make(engine.Actions, len(oldAcs))
|
||||
for index, oldAc := range oldAcs {
|
||||
a := &engine.Action{
|
||||
Id: oldAc.Id,
|
||||
ActionType: oldAc.ActionType,
|
||||
ExtraParameters: oldAc.ExtraParameters,
|
||||
ExpirationString: oldAc.ExpirationString,
|
||||
Filter: oldAc.Filter,
|
||||
Weight: oldAc.Weight,
|
||||
Balance: &engine.BalanceFilter{
|
||||
Uuid: oldAc.Balance.Uuid,
|
||||
ID: oldAc.Balance.ID,
|
||||
Type: oldAc.Balance.Type,
|
||||
Directions: oldAc.Balance.Directions,
|
||||
ExpirationDate: oldAc.Balance.ExpirationDate,
|
||||
Weight: oldAc.Balance.Weight,
|
||||
DestinationIDs: oldAc.Balance.DestinationIDs,
|
||||
RatingSubject: oldAc.Balance.RatingSubject,
|
||||
Categories: oldAc.Balance.Categories,
|
||||
SharedGroups: oldAc.Balance.SharedGroups,
|
||||
TimingIDs: oldAc.Balance.TimingIDs,
|
||||
Timings: oldAc.Balance.Timings,
|
||||
Disabled: oldAc.Balance.Disabled,
|
||||
Factor: oldAc.Balance.Factor,
|
||||
Blocker: oldAc.Balance.Blocker,
|
||||
},
|
||||
}
|
||||
if oldAc.Balance.Value != nil {
|
||||
a.Balance.Value = &utils.ValueFormula{Static: *oldAc.Balance.Value}
|
||||
}
|
||||
newAcs[index] = a
|
||||
}
|
||||
newAcsMap[key] = newAcs
|
||||
}
|
||||
// write data back
|
||||
for key, acs := range newAcsMap {
|
||||
result, err := mig.ms.Marshal(&acs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = mig.db.Cmd("SET", key, result).Err; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -153,7 +153,6 @@ func durRemoteRater(cd *engine.CallDescriptor) (time.Duration, error) {
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
runtime.GOMAXPROCS(runtime.NumCPU() - 1)
|
||||
|
||||
if *cpuprofile != "" {
|
||||
f, err := os.Create(*cpuprofile)
|
||||
|
||||
44
cmd/cgr-tester/parallel/parallel.go
Normal file
44
cmd/cgr-tester/parallel/parallel.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Print("Start!")
|
||||
var wg sync.WaitGroup
|
||||
for i := 1; i < 1002; i++ {
|
||||
go func(index int) {
|
||||
wg.Add(1)
|
||||
resp, err := http.Post("http://localhost:2080/jsonrpc", "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(`{"method": "ApierV1.SetAccount","params": [{"Tenant":"reglo","Account":"100%d","ActionPlanId":"PACKAGE_NEW_FOR795", "ReloadScheduler":false}], "id":%d}`, index, index))))
|
||||
if err != nil {
|
||||
log.Print("Post error: ", err)
|
||||
}
|
||||
contents, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Print("Body error: ", err)
|
||||
}
|
||||
log.Printf("SetAccount(%d): %s", index, string(contents))
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
for index := 1; index < 1002; index++ {
|
||||
resp, err := http.Post("http://localhost:2080/jsonrpc", "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(`{"method": "ApierV1.GetAccountActionPlan","params": [{"Tenant":"reglo","Account":"100%d"}], "id":%d}`, index, index))))
|
||||
if err != nil {
|
||||
log.Print("Post error: ", err)
|
||||
}
|
||||
contents, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Print("Body error: ", err)
|
||||
}
|
||||
log.Printf("GetAccountActionPlan(%d): %s", index, string(contents))
|
||||
}
|
||||
|
||||
log.Print("Done!")
|
||||
}
|
||||
@@ -25,9 +25,10 @@ import (
|
||||
)
|
||||
|
||||
type CdrcConfig struct {
|
||||
ID string // free-form text identifying this CDRC instance
|
||||
Enabled bool // Enable/Disable the profile
|
||||
DryRun bool // Do not post CDRs to the server
|
||||
Cdrs string // The address where CDRs can be reached
|
||||
CdrsConns []*HaPoolConfig // The address where CDRs can be reached
|
||||
CdrFormat string // The type of CDR file to process <csv|opensips_flatstore>
|
||||
FieldSeparator rune // The separator to use when reading csvs
|
||||
DataUsageMultiplyFactor float64 // Conversion factor for data usage
|
||||
@@ -51,14 +52,21 @@ func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
if jsnCfg.Id != nil {
|
||||
self.ID = *jsnCfg.Id
|
||||
}
|
||||
if jsnCfg.Enabled != nil {
|
||||
self.Enabled = *jsnCfg.Enabled
|
||||
}
|
||||
if jsnCfg.Dry_run != nil {
|
||||
self.DryRun = *jsnCfg.Dry_run
|
||||
}
|
||||
if jsnCfg.Cdrs != nil {
|
||||
self.Cdrs = *jsnCfg.Cdrs
|
||||
if jsnCfg.Cdrs_conns != nil {
|
||||
self.CdrsConns = make([]*HaPoolConfig, len(*jsnCfg.Cdrs_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Cdrs_conns {
|
||||
self.CdrsConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CdrsConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Cdr_format != nil {
|
||||
self.CdrFormat = *jsnCfg.Cdr_format
|
||||
@@ -125,8 +133,13 @@ func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error {
|
||||
// Clone itself into a new CdrcConfig
|
||||
func (self *CdrcConfig) Clone() *CdrcConfig {
|
||||
clnCdrc := new(CdrcConfig)
|
||||
clnCdrc.ID = self.ID
|
||||
clnCdrc.Enabled = self.Enabled
|
||||
clnCdrc.Cdrs = self.Cdrs
|
||||
clnCdrc.CdrsConns = make([]*HaPoolConfig, len(self.CdrsConns))
|
||||
for idx, cdrConn := range self.CdrsConns {
|
||||
clonedVal := *cdrConn
|
||||
clnCdrc.CdrsConns[idx] = &clonedVal
|
||||
}
|
||||
clnCdrc.CdrFormat = self.CdrFormat
|
||||
clnCdrc.FieldSeparator = self.FieldSeparator
|
||||
clnCdrc.DataUsageMultiplyFactor = self.DataUsageMultiplyFactor
|
||||
|
||||
@@ -7,25 +7,27 @@
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
"general": {
|
||||
"default_reqtype": "*pseudoprepaid", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
"default_request_type": "*pseudoprepaid", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
"cdrc": {
|
||||
"CDRC-CSV1": {
|
||||
"cdrc": [
|
||||
{
|
||||
"id": "CDRC-CSV1",
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"cdr_in_dir": "/tmp/cgrates/cdrc1/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgrates/cdrc1/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
"cdr_source_id": "csv1", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
},
|
||||
"CDRC-CSV2": {
|
||||
{
|
||||
"id": "CDRC-CSV2",
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"cdr_in_dir": "/tmp/cgrates/cdrc2/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgrates/cdrc2/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
@@ -38,13 +40,13 @@
|
||||
{"field_id": "Usage", "value": "~9:s/^(\\d+)$/${1}s/"},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
"sm_freeswitch": {
|
||||
"enabled": true, // starts SessionManager service: <true|false>
|
||||
"connections":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
{"server": "1.2.3.4:8021", "password": "ClueCon", "reconnects": 5},
|
||||
{"server": "2.3.4.5:8021", "password": "ClueCon", "reconnects": 5},
|
||||
"event_socket_conns":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
{"address": "1.2.3.4:8021", "password": "ClueCon", "reconnects": 5},
|
||||
{"address": "2.3.4.5:8021", "password": "ClueCon", "reconnects": 5},
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
{
|
||||
|
||||
"cdrc": {
|
||||
"CDRC-CSV2": {
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"cdr_in_dir": "/tmp/cgrates/cdrc2/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgrates/cdrc2/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
"data_usage_multiply_factor": 0.000976563,
|
||||
"cdr_source_id": "csv2", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
"content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"field_id": "ToR", "value": "~7:s/^(voice|data|sms|generic)$/*$1/"},
|
||||
{"field_id": "AnswerTime", "value": "2"},
|
||||
],
|
||||
},
|
||||
"CDRC-CSV3": {
|
||||
"cdrc": [
|
||||
{
|
||||
"id": "CDRC-CSV3",
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"cdr_in_dir": "/tmp/cgrates/cdrc3/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgrates/cdrc3/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
"cdr_source_id": "csv3", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
"sm_freeswitch": {
|
||||
"enabled": true, // starts SessionManager service: <true|false>
|
||||
"connections":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
{"server": "2.3.4.5:8021", "password": "ClueCon", "reconnects": 5},
|
||||
"event_socket_conns":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
{"address": "2.3.4.5:8021", "password": "ClueCon", "reconnects": 5},
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
493
config/config.go
493
config/config.go
@@ -60,6 +60,7 @@ func SetCgrConfig(cfg *CGRConfig) {
|
||||
|
||||
func NewDefaultCGRConfig() (*CGRConfig, error) {
|
||||
cfg := new(CGRConfig)
|
||||
cfg.InstanceID = utils.GenUUID()
|
||||
cfg.DataFolderPath = "/usr/share/cgrates/"
|
||||
cfg.SmGenericConfig = new(SmGenericConfig)
|
||||
cfg.SmFsConfig = new(SmFsConfig)
|
||||
@@ -84,9 +85,9 @@ func NewDefaultCGRConfig() (*CGRConfig, error) {
|
||||
return nil, err
|
||||
}
|
||||
cfg.dfltCdreProfile = cfg.CdreProfiles[utils.META_DEFAULT].Clone() // So default will stay unique, will have nil pointer in case of no defaults loaded which is an extra check
|
||||
cfg.dfltCdrcProfile = cfg.CdrcProfiles["/var/log/cgrates/cdrc/in"][utils.META_DEFAULT].Clone()
|
||||
dfltFsConnConfig = cfg.SmFsConfig.Connections[0] // We leave it crashing here on purpose if no Connection defaults defined
|
||||
dfltKamConnConfig = cfg.SmKamConfig.Connections[0]
|
||||
cfg.dfltCdrcProfile = cfg.CdrcProfiles["/var/log/cgrates/cdrc/in"][0].Clone()
|
||||
dfltFsConnConfig = cfg.SmFsConfig.EventSocketConns[0] // We leave it crashing here on purpose if no Connection defaults defined
|
||||
dfltKamConnConfig = cfg.SmKamConfig.EvapiConns[0]
|
||||
if err := cfg.checkConfigSanity(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -167,89 +168,90 @@ func NewCGRConfigFromFolder(cfgDir string) (*CGRConfig, error) {
|
||||
|
||||
// Holds system configuration, defaults are overwritten with values from config file if found
|
||||
type CGRConfig struct {
|
||||
TpDbType string
|
||||
TpDbHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
|
||||
TpDbPort string // The port to bind to.
|
||||
TpDbName string // The name of the database to connect to.
|
||||
TpDbUser string // The user to sign in as.
|
||||
TpDbPass string // The user's password.
|
||||
DataDbType string
|
||||
DataDbHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
|
||||
DataDbPort string // The port to bind to.
|
||||
DataDbName string // The name of the database to connect to.
|
||||
DataDbUser string // The user to sign in as.
|
||||
DataDbPass string // The user's password.
|
||||
LoadHistorySize int // Maximum number of records to archive in load history
|
||||
StorDBType string // Should reflect the database type used to store logs
|
||||
StorDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
|
||||
StorDBPort string // Th e port to bind to.
|
||||
StorDBName string // The name of the database to connect to.
|
||||
StorDBUser string // The user to sign in as.
|
||||
StorDBPass string // The user's password.
|
||||
StorDBMaxOpenConns int // Maximum database connections opened
|
||||
StorDBMaxIdleConns int // Maximum idle connections to keep opened
|
||||
StorDBCDRSIndexes []string
|
||||
DBDataEncoding string // The encoding used to store object data in strings: <msgpack|json>
|
||||
RPCJSONListen string // RPC JSON listening address
|
||||
RPCGOBListen string // RPC GOB listening address
|
||||
HTTPListen string // HTTP listening address
|
||||
DefaultReqType string // Use this request type if not defined on top
|
||||
DefaultCategory string // set default type of record
|
||||
DefaultTenant string // set default tenant
|
||||
DefaultSubject string // set default rating subject, useful in case of fallback
|
||||
DefaultTimezone string // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
Reconnects int // number of recconect attempts in case of connection lost <-1 for infinite | nb>
|
||||
ConnectAttempts int // number of initial connection attempts before giving up
|
||||
ResponseCacheTTL time.Duration // the life span of a cached response
|
||||
InternalTtl time.Duration // maximum duration to wait for internal connections before giving up
|
||||
RoundingDecimals int // Number of decimals to round end prices at
|
||||
HttpSkipTlsVerify bool // If enabled Http Client will accept any TLS certificate
|
||||
TpExportPath string // Path towards export folder for offline Tariff Plans
|
||||
HttpFailedDir string // Directory path where we store failed http requests
|
||||
MaxCallDuration time.Duration // The maximum call duration (used by responder when querying DerivedCharging) // ToDo: export it in configuration file
|
||||
RaterEnabled bool // start standalone server (no balancer)
|
||||
RaterBalancer string // balancer address host:port
|
||||
RaterCdrStats string // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234>
|
||||
RaterHistoryServer string
|
||||
RaterPubSubServer string
|
||||
RaterUserServer string
|
||||
RaterAliasesServer string
|
||||
RpSubjectPrefixMatching bool // enables prefix matching for the rating profile subject
|
||||
BalancerEnabled bool
|
||||
SchedulerEnabled bool
|
||||
CDRSEnabled bool // Enable CDR Server service
|
||||
CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs
|
||||
CDRSStoreCdrs bool // store cdrs in storDb
|
||||
CDRSRater string // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234>
|
||||
CDRSPubSub string // address where to reach the pubsub service: <""|internal|x.y.z.y:1234>
|
||||
CDRSUsers string // address where to reach the users service: <""|internal|x.y.z.y:1234>
|
||||
CDRSAliases string // address where to reach the aliases service: <""|internal|x.y.z.y:1234>
|
||||
CDRSStats string // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234>
|
||||
CDRSCdrReplication []*CdrReplicationCfg // Replicate raw CDRs to a number of servers
|
||||
CDRStatsEnabled bool // Enable CDR Stats service
|
||||
CDRStatsSaveInterval time.Duration // Save interval duration
|
||||
CdreProfiles map[string]*CdreConfig
|
||||
CdrcProfiles map[string]map[string]*CdrcConfig // Number of CDRC instances running imports, format map[dirPath]map[instanceName]{Configs}
|
||||
SmGenericConfig *SmGenericConfig
|
||||
SmFsConfig *SmFsConfig // SM-FreeSWITCH configuration
|
||||
SmKamConfig *SmKamConfig // SM-Kamailio Configuration
|
||||
SmOsipsConfig *SmOsipsConfig // SM-OpenSIPS Configuration
|
||||
diameterAgentCfg *DiameterAgentCfg // DiameterAgent configuration
|
||||
HistoryServer string // Address where to reach the master history server: <internal|x.y.z.y:1234>
|
||||
HistoryServerEnabled bool // Starts History as server: <true|false>.
|
||||
HistoryDir string // Location on disk where to store history files.
|
||||
HistorySaveInterval time.Duration // The timout duration between pubsub writes
|
||||
PubSubServerEnabled bool // Starts PubSub as server: <true|false>.
|
||||
AliasesServerEnabled bool // Starts PubSub as server: <true|false>.
|
||||
UserServerEnabled bool // Starts User as server: <true|false>
|
||||
UserServerIndexes []string // List of user profile field indexes
|
||||
MailerServer string // The server to use when sending emails out
|
||||
MailerAuthUser string // Authenticate to email server using this user
|
||||
MailerAuthPass string // Authenticate to email server with this password
|
||||
MailerFromAddr string // From address used when sending emails out
|
||||
DataFolderPath string // Path towards data folder, for tests internal usage, not loading out of .json options
|
||||
sureTaxCfg *SureTaxCfg // Load here SureTax configuration, as pointer so we can have runtime reloads in the future
|
||||
ConfigReloads map[string]chan struct{} // Signals to specific entities that a config reload should occur
|
||||
InstanceID string // Identifier for this engine instance
|
||||
TpDbType string
|
||||
TpDbHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
|
||||
TpDbPort string // The port to bind to.
|
||||
TpDbName string // The name of the database to connect to.
|
||||
TpDbUser string // The user to sign in as.
|
||||
TpDbPass string // The user's password.
|
||||
DataDbType string
|
||||
DataDbHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
|
||||
DataDbPort string // The port to bind to.
|
||||
DataDbName string // The name of the database to connect to.
|
||||
DataDbUser string // The user to sign in as.
|
||||
DataDbPass string // The user's password.
|
||||
LoadHistorySize int // Maximum number of records to archive in load history
|
||||
StorDBType string // Should reflect the database type used to store logs
|
||||
StorDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets.
|
||||
StorDBPort string // Th e port to bind to.
|
||||
StorDBName string // The name of the database to connect to.
|
||||
StorDBUser string // The user to sign in as.
|
||||
StorDBPass string // The user's password.
|
||||
StorDBMaxOpenConns int // Maximum database connections opened
|
||||
StorDBMaxIdleConns int // Maximum idle connections to keep opened
|
||||
StorDBCDRSIndexes []string
|
||||
DBDataEncoding string // The encoding used to store object data in strings: <msgpack|json>
|
||||
RPCJSONListen string // RPC JSON listening address
|
||||
RPCGOBListen string // RPC GOB listening address
|
||||
HTTPListen string // HTTP listening address
|
||||
DefaultReqType string // Use this request type if not defined on top
|
||||
DefaultCategory string // set default type of record
|
||||
DefaultTenant string // set default tenant
|
||||
DefaultTimezone string // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
Reconnects int // number of recconect attempts in case of connection lost <-1 for infinite | nb>
|
||||
ConnectAttempts int // number of initial connection attempts before giving up
|
||||
ResponseCacheTTL time.Duration // the life span of a cached response
|
||||
InternalTtl time.Duration // maximum duration to wait for internal connections before giving up
|
||||
RoundingDecimals int // Number of decimals to round end prices at
|
||||
HttpSkipTlsVerify bool // If enabled Http Client will accept any TLS certificate
|
||||
TpExportPath string // Path towards export folder for offline Tariff Plans
|
||||
HttpFailedDir string // Directory path where we store failed http requests
|
||||
MaxCallDuration time.Duration // The maximum call duration (used by responder when querying DerivedCharging) // ToDo: export it in configuration file
|
||||
RALsEnabled bool // start standalone server (no balancer)
|
||||
RALsBalancer string // balancer address host:port
|
||||
RALsCDRStatSConns []*HaPoolConfig // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234>
|
||||
RALsHistorySConns []*HaPoolConfig
|
||||
RALsPubSubSConns []*HaPoolConfig
|
||||
RALsUserSConns []*HaPoolConfig
|
||||
RALsAliasSConns []*HaPoolConfig
|
||||
RpSubjectPrefixMatching bool // enables prefix matching for the rating profile subject
|
||||
LcrSubjectPrefixMatching bool // enables prefix matching for the lcr subject
|
||||
BalancerEnabled bool
|
||||
SchedulerEnabled bool
|
||||
CDRSEnabled bool // Enable CDR Server service
|
||||
CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs
|
||||
CDRSStoreCdrs bool // store cdrs in storDb
|
||||
CDRSRaterConns []*HaPoolConfig // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234>
|
||||
CDRSPubSubSConns []*HaPoolConfig // address where to reach the pubsub service: <""|internal|x.y.z.y:1234>
|
||||
CDRSUserSConns []*HaPoolConfig // address where to reach the users service: <""|internal|x.y.z.y:1234>
|
||||
CDRSAliaseSConns []*HaPoolConfig // address where to reach the aliases service: <""|internal|x.y.z.y:1234>
|
||||
CDRSStatSConns []*HaPoolConfig // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234>
|
||||
CDRSCdrReplication []*CdrReplicationCfg // Replicate raw CDRs to a number of servers
|
||||
CDRStatsEnabled bool // Enable CDR Stats service
|
||||
CDRStatsSaveInterval time.Duration // Save interval duration
|
||||
CdreProfiles map[string]*CdreConfig
|
||||
CdrcProfiles map[string][]*CdrcConfig // Number of CDRC instances running imports, format map[dirPath][]{Configs}
|
||||
SmGenericConfig *SmGenericConfig
|
||||
SmFsConfig *SmFsConfig // SMFreeSWITCH configuration
|
||||
SmKamConfig *SmKamConfig // SM-Kamailio Configuration
|
||||
SmOsipsConfig *SmOsipsConfig // SMOpenSIPS Configuration
|
||||
diameterAgentCfg *DiameterAgentCfg // DiameterAgent configuration
|
||||
HistoryServer string // Address where to reach the master history server: <internal|x.y.z.y:1234>
|
||||
HistoryServerEnabled bool // Starts History as server: <true|false>.
|
||||
HistoryDir string // Location on disk where to store history files.
|
||||
HistorySaveInterval time.Duration // The timout duration between pubsub writes
|
||||
PubSubServerEnabled bool // Starts PubSub as server: <true|false>.
|
||||
AliasesServerEnabled bool // Starts PubSub as server: <true|false>.
|
||||
UserServerEnabled bool // Starts User as server: <true|false>
|
||||
UserServerIndexes []string // List of user profile field indexes
|
||||
MailerServer string // The server to use when sending emails out
|
||||
MailerAuthUser string // Authenticate to email server using this user
|
||||
MailerAuthPass string // Authenticate to email server with this password
|
||||
MailerFromAddr string // From address used when sending emails out
|
||||
DataFolderPath string // Path towards data folder, for tests internal usage, not loading out of .json options
|
||||
sureTaxCfg *SureTaxCfg // Load here SureTax configuration, as pointer so we can have runtime reloads in the future
|
||||
ConfigReloads map[string]chan struct{} // Signals to specific entities that a config reload should occur
|
||||
// Cache defaults loaded from json and needing clones
|
||||
dfltCdreProfile *CdreConfig // Default cdreConfig profile
|
||||
dfltCdrcProfile *CdrcConfig // Default cdrcConfig profile
|
||||
@@ -257,42 +259,62 @@ type CGRConfig struct {
|
||||
|
||||
func (self *CGRConfig) checkConfigSanity() error {
|
||||
// Rater checks
|
||||
if self.RaterEnabled {
|
||||
if self.RaterBalancer == utils.INTERNAL && !self.BalancerEnabled {
|
||||
if self.RALsEnabled {
|
||||
if self.RALsBalancer == utils.MetaInternal && !self.BalancerEnabled {
|
||||
return errors.New("Balancer not enabled but requested by Rater component.")
|
||||
}
|
||||
if self.RaterCdrStats == utils.INTERNAL && !self.CDRStatsEnabled {
|
||||
return errors.New("CDRStats not enabled but requested by Rater component.")
|
||||
for _, connCfg := range self.RALsCDRStatSConns {
|
||||
if connCfg.Address == utils.MetaInternal && !self.CDRStatsEnabled {
|
||||
return errors.New("CDRStats not enabled but requested by Rater component.")
|
||||
}
|
||||
}
|
||||
if self.RaterHistoryServer == utils.INTERNAL && !self.HistoryServerEnabled {
|
||||
return errors.New("History server not enabled but requested by Rater component.")
|
||||
for _, connCfg := range self.RALsHistorySConns {
|
||||
if connCfg.Address == utils.MetaInternal && !self.HistoryServerEnabled {
|
||||
return errors.New("History server not enabled but requested by Rater component.")
|
||||
}
|
||||
}
|
||||
if self.RaterPubSubServer == utils.INTERNAL && !self.PubSubServerEnabled {
|
||||
return errors.New("PubSub server not enabled but requested by Rater component.")
|
||||
for _, connCfg := range self.RALsPubSubSConns {
|
||||
if connCfg.Address == utils.MetaInternal && !self.PubSubServerEnabled {
|
||||
return errors.New("PubSub server not enabled but requested by Rater component.")
|
||||
}
|
||||
}
|
||||
if self.RaterAliasesServer == utils.INTERNAL && !self.AliasesServerEnabled {
|
||||
return errors.New("Aliases server not enabled but requested by Rater component.")
|
||||
for _, connCfg := range self.RALsAliasSConns {
|
||||
if connCfg.Address == utils.MetaInternal && !self.AliasesServerEnabled {
|
||||
return errors.New("Alias server not enabled but requested by Rater component.")
|
||||
}
|
||||
}
|
||||
if self.RaterUserServer == utils.INTERNAL && !self.UserServerEnabled {
|
||||
return errors.New("Users service not enabled but requested by Rater component.")
|
||||
for _, connCfg := range self.RALsUserSConns {
|
||||
if connCfg.Address == utils.MetaInternal && !self.UserServerEnabled {
|
||||
return errors.New("User service not enabled but requested by Rater component.")
|
||||
}
|
||||
}
|
||||
}
|
||||
// CDRServer checks
|
||||
if self.CDRSEnabled {
|
||||
if self.CDRSRater == utils.INTERNAL && !self.RaterEnabled {
|
||||
return errors.New("Rater not enabled but requested by CDRS component.")
|
||||
for _, cdrsRaterConn := range self.CDRSRaterConns {
|
||||
if cdrsRaterConn.Address == utils.MetaInternal && !self.RALsEnabled {
|
||||
return errors.New("RALs not enabled but requested by CDRS component.")
|
||||
}
|
||||
}
|
||||
if self.CDRSPubSub == utils.INTERNAL && !self.PubSubServerEnabled {
|
||||
return errors.New("PubSub service not enabled but requested by CDRS component.")
|
||||
for _, connCfg := range self.CDRSPubSubSConns {
|
||||
if connCfg.Address == utils.MetaInternal && !self.PubSubServerEnabled {
|
||||
return errors.New("PubSubS not enabled but requested by CDRS component.")
|
||||
}
|
||||
}
|
||||
if self.CDRSUsers == utils.INTERNAL && !self.UserServerEnabled {
|
||||
return errors.New("Users service not enabled but requested by CDRS component.")
|
||||
for _, connCfg := range self.CDRSUserSConns {
|
||||
if connCfg.Address == utils.MetaInternal && !self.UserServerEnabled {
|
||||
return errors.New("UserS not enabled but requested by CDRS component.")
|
||||
}
|
||||
}
|
||||
if self.CDRSAliases == utils.INTERNAL && !self.AliasesServerEnabled {
|
||||
return errors.New("Aliases service not enabled but requested by CDRS component.")
|
||||
for _, connCfg := range self.CDRSAliaseSConns {
|
||||
if connCfg.Address == utils.MetaInternal && !self.AliasesServerEnabled {
|
||||
return errors.New("AliaseS not enabled but requested by CDRS component.")
|
||||
}
|
||||
}
|
||||
if self.CDRSStats == utils.INTERNAL && !self.CDRStatsEnabled {
|
||||
return errors.New("CDRStats not enabled but requested by CDRS component.")
|
||||
for _, connCfg := range self.CDRSStatSConns {
|
||||
if connCfg.Address == utils.MetaInternal && !self.CDRStatsEnabled {
|
||||
return errors.New("CDRStatS not enabled but requested by CDRS component.")
|
||||
}
|
||||
}
|
||||
}
|
||||
// CDRC sanity checks
|
||||
@@ -301,10 +323,13 @@ func (self *CGRConfig) checkConfigSanity() error {
|
||||
if !cdrcInst.Enabled {
|
||||
continue
|
||||
}
|
||||
if len(cdrcInst.Cdrs) == 0 {
|
||||
return errors.New("CdrC enabled but no CDRS defined!")
|
||||
} else if cdrcInst.Cdrs == utils.INTERNAL && !self.CDRSEnabled {
|
||||
return errors.New("CDRS not enabled but referenced from CDRC")
|
||||
if len(cdrcInst.CdrsConns) == 0 {
|
||||
return fmt.Errorf("<CDRC> Instance: %s, CdrC enabled but no CDRS defined!", cdrcInst.ID)
|
||||
}
|
||||
for _, conn := range cdrcInst.CdrsConns {
|
||||
if conn.Address == utils.MetaInternal && !self.CDRSEnabled {
|
||||
return errors.New("CDRS not enabled but referenced from CDRC")
|
||||
}
|
||||
}
|
||||
if len(cdrcInst.ContentFields) == 0 {
|
||||
return errors.New("CdrC enabled but no fields to be processed defined!")
|
||||
@@ -320,70 +345,94 @@ func (self *CGRConfig) checkConfigSanity() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
// SM-Generic checks
|
||||
// SMGeneric checks
|
||||
if self.SmGenericConfig.Enabled {
|
||||
if len(self.SmGenericConfig.HaRater) == 0 {
|
||||
return errors.New("Rater definition is mandatory!")
|
||||
if len(self.SmGenericConfig.RALsConns) == 0 {
|
||||
return errors.New("<SMGeneric> RALs definition is mandatory!")
|
||||
}
|
||||
if len(self.SmGenericConfig.HaCdrs) == 0 {
|
||||
return errors.New("Cdrs definition is mandatory!")
|
||||
for _, smgRALsConn := range self.SmGenericConfig.RALsConns {
|
||||
if smgRALsConn.Address == utils.MetaInternal && !self.RALsEnabled {
|
||||
return errors.New("<SMGeneric> RALs not enabled but requested by SMGeneric component.")
|
||||
}
|
||||
}
|
||||
if self.SmGenericConfig.HaRater[0].Server == utils.INTERNAL && !self.RaterEnabled {
|
||||
return errors.New("Rater not enabled but requested by SM-Generic component.")
|
||||
if len(self.SmGenericConfig.CDRsConns) == 0 {
|
||||
return errors.New("<SMGeneric> CDRs definition is mandatory!")
|
||||
}
|
||||
if self.SmGenericConfig.HaCdrs[0].Server == utils.INTERNAL && !self.CDRSEnabled {
|
||||
return errors.New("CDRS not enabled but referenced by SM-Generic component")
|
||||
for _, smgCDRSConn := range self.SmGenericConfig.CDRsConns {
|
||||
if smgCDRSConn.Address == utils.MetaInternal && !self.CDRSEnabled {
|
||||
return errors.New("<SMGeneric> CDRS not enabled but referenced by SMGeneric component")
|
||||
}
|
||||
}
|
||||
}
|
||||
// SM-FreeSWITCH checks
|
||||
// SMFreeSWITCH checks
|
||||
if self.SmFsConfig.Enabled {
|
||||
if len(self.SmFsConfig.HaRater) == 0 {
|
||||
return errors.New("Rater definition is mandatory!")
|
||||
if len(self.SmFsConfig.RALsConns) == 0 {
|
||||
return errors.New("<SMFreeSWITCH> RALs definition is mandatory!")
|
||||
}
|
||||
if len(self.SmFsConfig.HaCdrs) == 0 {
|
||||
return errors.New("Cdrs definition is mandatory!")
|
||||
for _, smFSRaterConn := range self.SmFsConfig.RALsConns {
|
||||
if smFSRaterConn.Address == utils.MetaInternal && !self.RALsEnabled {
|
||||
return errors.New("<SMFreeSWITCH> RALs not enabled but requested by SMFreeSWITCH component.")
|
||||
}
|
||||
}
|
||||
if self.SmFsConfig.HaRater[0].Server == utils.INTERNAL && !self.RaterEnabled {
|
||||
return errors.New("Rater not enabled but requested by SM-FreeSWITCH component.")
|
||||
if len(self.SmFsConfig.CDRsConns) == 0 {
|
||||
return errors.New("<SMFreeSWITCH> CDRS definition is mandatory!")
|
||||
}
|
||||
if self.SmFsConfig.HaCdrs[0].Server == utils.INTERNAL && !self.CDRSEnabled {
|
||||
return errors.New("CDRS not enabled but referenced by SM-FreeSWITCH component")
|
||||
for _, smFSCDRSConn := range self.SmFsConfig.CDRsConns {
|
||||
if smFSCDRSConn.Address == utils.MetaInternal && !self.CDRSEnabled {
|
||||
return errors.New("CDRS not enabled but referenced by SMFreeSWITCH component")
|
||||
}
|
||||
}
|
||||
}
|
||||
// SM-Kamailio checks
|
||||
if self.SmKamConfig.Enabled {
|
||||
if len(self.SmKamConfig.HaRater) == 0 {
|
||||
if len(self.SmKamConfig.RALsConns) == 0 {
|
||||
return errors.New("Rater definition is mandatory!")
|
||||
}
|
||||
if len(self.SmKamConfig.HaCdrs) == 0 {
|
||||
for _, smKamRaterConn := range self.SmKamConfig.RALsConns {
|
||||
if smKamRaterConn.Address == utils.MetaInternal && !self.RALsEnabled {
|
||||
return errors.New("Rater not enabled but requested by SM-Kamailio component.")
|
||||
}
|
||||
}
|
||||
if len(self.SmKamConfig.CDRsConns) == 0 {
|
||||
return errors.New("Cdrs definition is mandatory!")
|
||||
}
|
||||
if self.SmKamConfig.HaRater[0].Server == utils.INTERNAL && !self.RaterEnabled {
|
||||
return errors.New("Rater not enabled but requested by SM-Kamailio component.")
|
||||
}
|
||||
if self.SmKamConfig.HaCdrs[0].Server == utils.INTERNAL && !self.CDRSEnabled {
|
||||
return errors.New("CDRS not enabled but referenced by SM-Kamailio component")
|
||||
for _, smKamCDRSConn := range self.SmKamConfig.CDRsConns {
|
||||
if smKamCDRSConn.Address == utils.MetaInternal && !self.CDRSEnabled {
|
||||
return errors.New("CDRS not enabled but referenced by SM-Kamailio component")
|
||||
}
|
||||
}
|
||||
}
|
||||
// SM-OpenSIPS checks
|
||||
// SMOpenSIPS checks
|
||||
if self.SmOsipsConfig.Enabled {
|
||||
if len(self.SmOsipsConfig.HaRater) == 0 {
|
||||
return errors.New("Rater definition is mandatory!")
|
||||
if len(self.SmOsipsConfig.RALsConns) == 0 {
|
||||
return errors.New("<SMOpenSIPS> Rater definition is mandatory!")
|
||||
}
|
||||
if len(self.SmOsipsConfig.HaCdrs) == 0 {
|
||||
return errors.New("Cdrs definition is mandatory!")
|
||||
for _, smOsipsRaterConn := range self.SmOsipsConfig.RALsConns {
|
||||
if smOsipsRaterConn.Address == utils.MetaInternal && !self.RALsEnabled {
|
||||
return errors.New("<SMOpenSIPS> RALs not enabled but requested by SMOpenSIPS component.")
|
||||
}
|
||||
}
|
||||
if self.SmOsipsConfig.HaRater[0].Server == utils.INTERNAL && !self.RaterEnabled {
|
||||
return errors.New("Rater not enabled but requested by SM-OpenSIPS component.")
|
||||
if len(self.SmOsipsConfig.CDRsConns) == 0 {
|
||||
return errors.New("<SMOpenSIPS> CDRs definition is mandatory!")
|
||||
}
|
||||
if self.SmOsipsConfig.HaCdrs[0].Server == utils.INTERNAL && !self.CDRSEnabled {
|
||||
return errors.New("CDRS not enabled but referenced by SM-OpenSIPS component")
|
||||
|
||||
for _, smOsipsCDRSConn := range self.SmOsipsConfig.CDRsConns {
|
||||
if smOsipsCDRSConn.Address == utils.MetaInternal && !self.CDRSEnabled {
|
||||
return errors.New("<SMOpenSIPS> CDRS not enabled but referenced by SMOpenSIPS component")
|
||||
}
|
||||
}
|
||||
}
|
||||
// DAgent checks
|
||||
if self.diameterAgentCfg.Enabled {
|
||||
if self.diameterAgentCfg.SMGeneric == utils.INTERNAL && !self.SmGenericConfig.Enabled {
|
||||
return errors.New("SMGeneric not enabled but referenced by DiameterAgent component")
|
||||
for _, daSMGConn := range self.diameterAgentCfg.SMGenericConns {
|
||||
if daSMGConn.Address == utils.MetaInternal && !self.SmGenericConfig.Enabled {
|
||||
return errors.New("SMGeneric not enabled but referenced by DiameterAgent component")
|
||||
}
|
||||
}
|
||||
for _, daPubSubSConn := range self.diameterAgentCfg.PubSubConns {
|
||||
if daPubSubSConn.Address == utils.MetaInternal && !self.PubSubServerEnabled {
|
||||
return errors.New("PubSubS not enabled but requested by DiameterAgent component.")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -423,7 +472,7 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
return err
|
||||
}
|
||||
|
||||
jsnRaterCfg, err := jsnCfg.RaterJsonCfg()
|
||||
jsnRALsCfg, err := jsnCfg.RalsJsonCfg()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -525,8 +574,8 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
if jsnTpDbCfg.Db_user != nil {
|
||||
self.TpDbUser = *jsnTpDbCfg.Db_user
|
||||
}
|
||||
if jsnTpDbCfg.Db_passwd != nil {
|
||||
self.TpDbPass = *jsnTpDbCfg.Db_passwd
|
||||
if jsnTpDbCfg.Db_password != nil {
|
||||
self.TpDbPass = *jsnTpDbCfg.Db_password
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,8 +595,8 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
if jsnDataDbCfg.Db_user != nil {
|
||||
self.DataDbUser = *jsnDataDbCfg.Db_user
|
||||
}
|
||||
if jsnDataDbCfg.Db_passwd != nil {
|
||||
self.DataDbPass = *jsnDataDbCfg.Db_passwd
|
||||
if jsnDataDbCfg.Db_password != nil {
|
||||
self.DataDbPass = *jsnDataDbCfg.Db_password
|
||||
}
|
||||
if jsnDataDbCfg.Load_history_size != nil {
|
||||
self.LoadHistorySize = *jsnDataDbCfg.Load_history_size
|
||||
@@ -570,8 +619,8 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
if jsnStorDbCfg.Db_user != nil {
|
||||
self.StorDBUser = *jsnStorDbCfg.Db_user
|
||||
}
|
||||
if jsnStorDbCfg.Db_passwd != nil {
|
||||
self.StorDBPass = *jsnStorDbCfg.Db_passwd
|
||||
if jsnStorDbCfg.Db_password != nil {
|
||||
self.StorDBPass = *jsnStorDbCfg.Db_password
|
||||
}
|
||||
if jsnStorDbCfg.Max_open_conns != nil {
|
||||
self.StorDBMaxOpenConns = *jsnStorDbCfg.Max_open_conns
|
||||
@@ -588,8 +637,8 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
if jsnGeneralCfg.Dbdata_encoding != nil {
|
||||
self.DBDataEncoding = *jsnGeneralCfg.Dbdata_encoding
|
||||
}
|
||||
if jsnGeneralCfg.Default_reqtype != nil {
|
||||
self.DefaultReqType = *jsnGeneralCfg.Default_reqtype
|
||||
if jsnGeneralCfg.Default_request_type != nil {
|
||||
self.DefaultReqType = *jsnGeneralCfg.Default_request_type
|
||||
}
|
||||
if jsnGeneralCfg.Default_category != nil {
|
||||
self.DefaultCategory = *jsnGeneralCfg.Default_category
|
||||
@@ -597,9 +646,6 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
if jsnGeneralCfg.Default_tenant != nil {
|
||||
self.DefaultTenant = *jsnGeneralCfg.Default_tenant
|
||||
}
|
||||
if jsnGeneralCfg.Default_subject != nil {
|
||||
self.DefaultSubject = *jsnGeneralCfg.Default_subject
|
||||
}
|
||||
if jsnGeneralCfg.Connect_attempts != nil {
|
||||
self.ConnectAttempts = *jsnGeneralCfg.Connect_attempts
|
||||
}
|
||||
@@ -645,30 +691,53 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
}
|
||||
}
|
||||
|
||||
if jsnRaterCfg != nil {
|
||||
if jsnRaterCfg.Enabled != nil {
|
||||
self.RaterEnabled = *jsnRaterCfg.Enabled
|
||||
if jsnRALsCfg != nil {
|
||||
if jsnRALsCfg.Enabled != nil {
|
||||
self.RALsEnabled = *jsnRALsCfg.Enabled
|
||||
}
|
||||
if jsnRaterCfg.Balancer != nil {
|
||||
self.RaterBalancer = *jsnRaterCfg.Balancer
|
||||
if jsnRALsCfg.Balancer != nil {
|
||||
self.RALsBalancer = *jsnRALsCfg.Balancer
|
||||
}
|
||||
if jsnRaterCfg.Cdrstats != nil {
|
||||
self.RaterCdrStats = *jsnRaterCfg.Cdrstats
|
||||
if jsnRALsCfg.Cdrstats_conns != nil {
|
||||
self.RALsCDRStatSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Cdrstats_conns))
|
||||
for idx, jsnHaCfg := range *jsnRALsCfg.Cdrstats_conns {
|
||||
self.RALsCDRStatSConns[idx] = NewDfltHaPoolConfig()
|
||||
self.RALsCDRStatSConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnRaterCfg.Historys != nil {
|
||||
self.RaterHistoryServer = *jsnRaterCfg.Historys
|
||||
if jsnRALsCfg.Historys_conns != nil {
|
||||
self.RALsHistorySConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Historys_conns))
|
||||
for idx, jsnHaCfg := range *jsnRALsCfg.Historys_conns {
|
||||
self.RALsHistorySConns[idx] = NewDfltHaPoolConfig()
|
||||
self.RALsHistorySConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnRaterCfg.Pubsubs != nil {
|
||||
self.RaterPubSubServer = *jsnRaterCfg.Pubsubs
|
||||
if jsnRALsCfg.Pubsubs_conns != nil {
|
||||
self.RALsPubSubSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Pubsubs_conns))
|
||||
for idx, jsnHaCfg := range *jsnRALsCfg.Pubsubs_conns {
|
||||
self.RALsPubSubSConns[idx] = NewDfltHaPoolConfig()
|
||||
self.RALsPubSubSConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnRaterCfg.Aliases != nil {
|
||||
self.RaterAliasesServer = *jsnRaterCfg.Aliases
|
||||
if jsnRALsCfg.Aliases_conns != nil {
|
||||
self.RALsAliasSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Aliases_conns))
|
||||
for idx, jsnHaCfg := range *jsnRALsCfg.Aliases_conns {
|
||||
self.RALsAliasSConns[idx] = NewDfltHaPoolConfig()
|
||||
self.RALsAliasSConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnRaterCfg.Users != nil {
|
||||
self.RaterUserServer = *jsnRaterCfg.Users
|
||||
if jsnRALsCfg.Users_conns != nil {
|
||||
self.RALsUserSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Users_conns))
|
||||
for idx, jsnHaCfg := range *jsnRALsCfg.Users_conns {
|
||||
self.RALsUserSConns[idx] = NewDfltHaPoolConfig()
|
||||
self.RALsUserSConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnRaterCfg.Rp_subject_prefix_matching != nil {
|
||||
self.RpSubjectPrefixMatching = *jsnRaterCfg.Rp_subject_prefix_matching
|
||||
if jsnRALsCfg.Rp_subject_prefix_matching != nil {
|
||||
self.RpSubjectPrefixMatching = *jsnRALsCfg.Rp_subject_prefix_matching
|
||||
}
|
||||
if jsnRALsCfg.Lcr_subject_prefix_matching != nil {
|
||||
self.LcrSubjectPrefixMatching = *jsnRALsCfg.Lcr_subject_prefix_matching
|
||||
}
|
||||
}
|
||||
|
||||
@@ -692,20 +761,40 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
if jsnCdrsCfg.Store_cdrs != nil {
|
||||
self.CDRSStoreCdrs = *jsnCdrsCfg.Store_cdrs
|
||||
}
|
||||
if jsnCdrsCfg.Rater != nil {
|
||||
self.CDRSRater = *jsnCdrsCfg.Rater
|
||||
if jsnCdrsCfg.Rals_conns != nil {
|
||||
self.CDRSRaterConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Rals_conns))
|
||||
for idx, jsnHaCfg := range *jsnCdrsCfg.Rals_conns {
|
||||
self.CDRSRaterConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CDRSRaterConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCdrsCfg.Pubsubs != nil {
|
||||
self.CDRSPubSub = *jsnCdrsCfg.Pubsubs
|
||||
if jsnCdrsCfg.Pubsubs_conns != nil {
|
||||
self.CDRSPubSubSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Pubsubs_conns))
|
||||
for idx, jsnHaCfg := range *jsnCdrsCfg.Pubsubs_conns {
|
||||
self.CDRSPubSubSConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CDRSPubSubSConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCdrsCfg.Users != nil {
|
||||
self.CDRSUsers = *jsnCdrsCfg.Users
|
||||
if jsnCdrsCfg.Users_conns != nil {
|
||||
self.CDRSUserSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Users_conns))
|
||||
for idx, jsnHaCfg := range *jsnCdrsCfg.Users_conns {
|
||||
self.CDRSUserSConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CDRSUserSConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCdrsCfg.Aliases != nil {
|
||||
self.CDRSAliases = *jsnCdrsCfg.Aliases
|
||||
if jsnCdrsCfg.Aliases_conns != nil {
|
||||
self.CDRSAliaseSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Aliases_conns))
|
||||
for idx, jsnHaCfg := range *jsnCdrsCfg.Aliases_conns {
|
||||
self.CDRSAliaseSConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CDRSAliaseSConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCdrsCfg.Cdrstats != nil {
|
||||
self.CDRSStats = *jsnCdrsCfg.Cdrstats
|
||||
if jsnCdrsCfg.Cdrstats_conns != nil {
|
||||
self.CDRSStatSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Cdrstats_conns))
|
||||
for idx, jsnHaCfg := range *jsnCdrsCfg.Cdrstats_conns {
|
||||
self.CDRSStatSConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CDRSStatSConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCdrsCfg.Cdr_replication != nil {
|
||||
self.CDRSCdrReplication = make([]*CdrReplicationCfg, len(*jsnCdrsCfg.Cdr_replication))
|
||||
@@ -714,8 +803,8 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
if rplJsonCfg.Transport != nil {
|
||||
self.CDRSCdrReplication[idx].Transport = *rplJsonCfg.Transport
|
||||
}
|
||||
if rplJsonCfg.Server != nil {
|
||||
self.CDRSCdrReplication[idx].Server = *rplJsonCfg.Server
|
||||
if rplJsonCfg.Address != nil {
|
||||
self.CDRSCdrReplication[idx].Address = *rplJsonCfg.Address
|
||||
}
|
||||
if rplJsonCfg.Synchronous != nil {
|
||||
self.CDRSCdrReplication[idx].Synchronous = *rplJsonCfg.Synchronous
|
||||
@@ -760,28 +849,26 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if jsnCdrcCfg != nil {
|
||||
if self.CdrcProfiles == nil {
|
||||
self.CdrcProfiles = make(map[string]map[string]*CdrcConfig)
|
||||
self.CdrcProfiles = make(map[string][]*CdrcConfig)
|
||||
}
|
||||
for profileName, jsnCrc1Cfg := range jsnCdrcCfg {
|
||||
for _, jsnCrc1Cfg := range jsnCdrcCfg {
|
||||
if _, hasDir := self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir]; !hasDir {
|
||||
self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir] = make(map[string]*CdrcConfig)
|
||||
self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir] = make([]*CdrcConfig, 0)
|
||||
}
|
||||
if _, hasProfile := self.CdrcProfiles[profileName]; !hasProfile {
|
||||
if profileName == utils.META_DEFAULT {
|
||||
self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir][profileName] = new(CdrcConfig)
|
||||
} else {
|
||||
self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir][profileName] = self.dfltCdrcProfile.Clone() // Clone default so we do not inherit pointers
|
||||
}
|
||||
var cdrcInstCfg *CdrcConfig
|
||||
if *jsnCrc1Cfg.Id == utils.META_DEFAULT && self.dfltCdrcProfile == nil {
|
||||
cdrcInstCfg = new(CdrcConfig)
|
||||
} else {
|
||||
cdrcInstCfg = self.dfltCdrcProfile.Clone() // Clone default so we do not inherit pointers
|
||||
}
|
||||
if err = self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir][profileName].loadFromJsonCfg(jsnCrc1Cfg); err != nil {
|
||||
if err := cdrcInstCfg.loadFromJsonCfg(jsnCrc1Cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir] = append(self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir], cdrcInstCfg)
|
||||
}
|
||||
}
|
||||
|
||||
if jsnSmGenericCfg != nil {
|
||||
if err := self.SmGenericConfig.loadFromJsonCfg(jsnSmGenericCfg); err != nil {
|
||||
return err
|
||||
@@ -853,8 +940,8 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
|
||||
if jsnMailerCfg.Auth_user != nil {
|
||||
self.MailerAuthUser = *jsnMailerCfg.Auth_user
|
||||
}
|
||||
if jsnMailerCfg.Auth_passwd != nil {
|
||||
self.MailerAuthPass = *jsnMailerCfg.Auth_passwd
|
||||
if jsnMailerCfg.Auth_password != nil {
|
||||
self.MailerAuthPass = *jsnMailerCfg.Auth_password
|
||||
}
|
||||
if jsnMailerCfg.From_address != nil {
|
||||
self.MailerFromAddr = *jsnMailerCfg.From_address
|
||||
|
||||
@@ -29,18 +29,17 @@ const CGRATES_CFG_JSON = `
|
||||
|
||||
"general": {
|
||||
"http_skip_tls_verify": false, // if enabled Http Client will accept any TLS certificate
|
||||
"rounding_decimals": 5, // system level precision for floats
|
||||
"rounding_decimals": 5, // system level precision for floats
|
||||
"dbdata_encoding": "msgpack", // encoding used to store object data in strings: <msgpack|json>
|
||||
"tpexport_dir": "/var/log/cgrates/tpe", // path towards export folder for offline Tariff Plans
|
||||
"http_failed_dir": "/var/log/cgrates/http_failed", // directory path where we store failed http requests
|
||||
"default_reqtype": "*rated", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
"default_category": "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
|
||||
"default_request_type": "*rated", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
"default_category": "call", // default category to consider when missing from requests
|
||||
"default_tenant": "cgrates.org", // default tenant to consider when missing from requests
|
||||
"default_timezone": "Local", // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
"connect_attempts": 3, // initial server connect attempts
|
||||
"reconnects": -1, // number of retries in case of connection lost
|
||||
"response_cache_ttl": "3s", // the life span of a cached response
|
||||
"response_cache_ttl": "0s", // the life span of a cached response
|
||||
"internal_ttl": "2m", // maximum duration to wait for internal connections before giving up
|
||||
},
|
||||
|
||||
@@ -58,7 +57,7 @@ const CGRATES_CFG_JSON = `
|
||||
"db_port": 6379, // port to reach the tariffplan_db
|
||||
"db_name": "10", // tariffplan_db name to connect to
|
||||
"db_user": "", // sername to use when connecting to tariffplan_db
|
||||
"db_passwd": "", // password to use when connecting to tariffplan_db
|
||||
"db_password": "", // password to use when connecting to tariffplan_db
|
||||
},
|
||||
|
||||
|
||||
@@ -68,7 +67,7 @@ const CGRATES_CFG_JSON = `
|
||||
"db_port": 6379, // data_db port to reach the database
|
||||
"db_name": "11", // data_db database name to connect to
|
||||
"db_user": "", // username to use when connecting to data_db
|
||||
"db_passwd": "", // password to use when connecting to data_db
|
||||
"db_password": "", // password to use when connecting to data_db
|
||||
"load_history_size": 10, // Number of records in the load history
|
||||
},
|
||||
|
||||
@@ -79,7 +78,7 @@ const CGRATES_CFG_JSON = `
|
||||
"db_port": 3306, // the port to reach the stordb
|
||||
"db_name": "cgrates", // stor database name
|
||||
"db_user": "cgrates", // username to use when connecting to stordb
|
||||
"db_passwd": "CGRateS.org", // password to use when connecting to stordb
|
||||
"db_password": "CGRateS.org", // password to use when connecting to stordb
|
||||
"max_open_conns": 100, // maximum database connections opened
|
||||
"max_idle_conns": 10, // maximum database connections idle
|
||||
"cdrs_indexes": [], // indexes on cdrs table to speed up queries, used only in case of mongo
|
||||
@@ -91,15 +90,16 @@ const CGRATES_CFG_JSON = `
|
||||
},
|
||||
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": false, // enable Rater service: <true|false>
|
||||
"balancer": "", // register to balancer as worker: <""|internal|x.y.z.y:1234>
|
||||
"cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality: <""|internal|x.y.z.y:1234>
|
||||
"historys": "", // address where to reach the history service, empty to disable history functionality: <""|internal|x.y.z.y:1234>
|
||||
"pubsubs": "", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
|
||||
"users": "", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
|
||||
"aliases": "", // address where to reach the aliases service, empty to disable aliases functionality: <""|internal|x.y.z.y:1234>
|
||||
"rp_subject_prefix_matching": false // enables prefix matching for the rating profile subject
|
||||
"balancer": "", // register to balancer as worker: <""|*internal|x.y.z.y:1234>
|
||||
"cdrstats_conns": [], // address where to reach the cdrstats service, empty to disable stats functionality: <""|*internal|x.y.z.y:1234>
|
||||
"historys_conns": [], // address where to reach the history service, empty to disable history functionality: <""|*internal|x.y.z.y:1234>
|
||||
"pubsubs_conns": [], // address where to reach the pubusb service, empty to disable pubsub functionality: <""|*internal|x.y.z.y:1234>
|
||||
"users_conns": [], // address where to reach the user service, empty to disable user profile functionality: <""|*internal|x.y.z.y:1234>
|
||||
"aliases_conns": [], // address where to reach the aliases service, empty to disable aliases functionality: <""|*internal|x.y.z.y:1234>
|
||||
"rp_subject_prefix_matching": false, // enables prefix matching for the rating profile subject
|
||||
"lcr_subject_prefix_matching": false // enables prefix matching for the lcr subject
|
||||
},
|
||||
|
||||
|
||||
@@ -112,12 +112,14 @@ const CGRATES_CFG_JSON = `
|
||||
"enabled": false, // start the CDR Server service: <true|false>
|
||||
"extra_fields": [], // extra fields to store in CDRs for non-generic CDRs
|
||||
"store_cdrs": true, // store cdrs in storDb
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
"pubsubs": "", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
|
||||
"users": "", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
|
||||
"aliases": "", // address where to reach the aliases service, empty to disable aliases functionality: <""|internal|x.y.z.y:1234>
|
||||
"cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
"cdr_replication":[], // replicate the raw CDR to a number of servers
|
||||
"rals_conns": [
|
||||
{"address": "*internal"} // address where to reach the Rater for cost calculation, empty to disable functionality: <""|*internal|x.y.z.y:1234>
|
||||
],
|
||||
"pubsubs_conns": [], // address where to reach the pubusb service, empty to disable pubsub functionality: <""|*internal|x.y.z.y:1234>
|
||||
"users_conns": [], // address where to reach the user service, empty to disable user profile functionality: <""|*internal|x.y.z.y:1234>
|
||||
"aliases_conns": [], // address where to reach the aliases service, empty to disable aliases functionality: <""|*internal|x.y.z.y:1234>
|
||||
"cdrstats_conns": [], // address where to reach the cdrstats service, empty to disable stats functionality<""|*internal|x.y.z.y:1234>
|
||||
"cdr_replication":[] // replicate the raw CDR to a number of servers
|
||||
},
|
||||
|
||||
|
||||
@@ -133,7 +135,7 @@ const CGRATES_CFG_JSON = `
|
||||
"field_separator": ",",
|
||||
"data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes)
|
||||
"sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems)
|
||||
"mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems)
|
||||
"mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems)
|
||||
"generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems)
|
||||
"cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
|
||||
"cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding
|
||||
@@ -164,11 +166,14 @@ const CGRATES_CFG_JSON = `
|
||||
},
|
||||
|
||||
|
||||
"cdrc": {
|
||||
"*default": {
|
||||
"cdrc": [
|
||||
{
|
||||
"id": "*default", // identifier of the CDRC runner
|
||||
"enabled": false, // enable CDR client functionality
|
||||
"dry_run": false, // do not send the CDRs to CDRS, just parse them
|
||||
"cdrs": "internal", // address where to reach CDR server. <internal|x.y.z.y:1234>
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"} // address where to reach CDR server. <*internal|x.y.z.y:1234>
|
||||
],
|
||||
"cdr_format": "csv", // CDR file format <csv|freeswitch_csv|fwv|opensips_flatstore>
|
||||
"field_separator": ",", // separator used in case of csv files
|
||||
"timezone": "", // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
@@ -198,52 +203,67 @@ const CGRATES_CFG_JSON = `
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "13", "mandatory": true},
|
||||
],
|
||||
"trailer_fields": [], // template of the import trailer fields
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
"sm_generic": {
|
||||
"enabled": false, // starts SessionManager service: <true|false>
|
||||
"listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests
|
||||
"rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
"cdrs": "internal", // address where to reach CDR Server <""|internal|x.y.z.y:1234>
|
||||
"rals_conns": [
|
||||
{"address": "*internal"} // address where to reach the Rater <""|*internal|127.0.0.1:2013>
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <*internal|x.y.z.y:1234>
|
||||
],
|
||||
"debit_interval": "0s", // interval to perform debits on.
|
||||
"min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
"max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
"session_ttl": "0s", // time after a session with no updates is terminated, not defined by default
|
||||
//"session_ttl_last_used": "", // tweak LastUsed for sessions timing-out, not defined by default
|
||||
//"session_ttl_usage": "", // tweak Usage for sessions timing-out, not defined by default
|
||||
},
|
||||
|
||||
|
||||
"sm_freeswitch": {
|
||||
"enabled": false, // starts SessionManager service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
"cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
|
||||
"create_cdr": false, // create CDR out of events and sends it to CDRS component
|
||||
"extra_fields": [], // extra fields to store in auth/CDRs when creating them
|
||||
"debit_interval": "10s", // interval to perform debits on.
|
||||
"min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
"max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
"min_dur_low_balance": "5s", // threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval)
|
||||
"low_balance_ann_file": "", // file to be played when low balance is reached for prepaid calls
|
||||
"empty_balance_context": "", // if defined, prepaid calls will be transfered to this context on empty balance
|
||||
"empty_balance_ann_file": "", // file to be played before disconnecting prepaid calls on empty balance (applies only if no context defined)
|
||||
"subscribe_park": true, // subscribe via fsock to receive park events
|
||||
"channel_sync_interval": "5m", // sync channels with freeswitch regularly
|
||||
"max_wait_connection": "2s", // maximum duration to wait for a connection to be retrieved from the pool
|
||||
"connections":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
{"server": "127.0.0.1:8021", "password": "ClueCon", "reconnects": 5}
|
||||
"rals_conns": [
|
||||
{"address": "*internal"} // address where to reach the Rater <""|*internal|127.0.0.1:2013>
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <*internal|x.y.z.y:1234>
|
||||
],
|
||||
"create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
"extra_fields": [], // extra fields to store in auth/CDRs when creating them
|
||||
"debit_interval": "10s", // interval to perform debits on.
|
||||
"min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
"max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
"min_dur_low_balance": "5s", // threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval)
|
||||
"low_balance_ann_file": "", // file to be played when low balance is reached for prepaid calls
|
||||
"empty_balance_context": "", // if defined, prepaid calls will be transfered to this context on empty balance
|
||||
"empty_balance_ann_file": "", // file to be played before disconnecting prepaid calls on empty balance (applies only if no context defined)
|
||||
"subscribe_park": true, // subscribe via fsock to receive park events
|
||||
"channel_sync_interval": "5m", // sync channels with freeswitch regularly
|
||||
"max_wait_connection": "2s", // maximum duration to wait for a connection to be retrieved from the pool
|
||||
"event_socket_conns":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
{"address": "127.0.0.1:8021", "password": "ClueCon", "reconnects": 5}
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
"sm_kamailio": {
|
||||
"enabled": false, // starts SessionManager service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
"cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
|
||||
"create_cdr": false, // create CDR out of events and sends it to CDRS component
|
||||
"debit_interval": "10s", // interval to perform debits on.
|
||||
"min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
"max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
"connections":[ // instantiate connections to multiple Kamailio servers
|
||||
{"evapi_addr": "127.0.0.1:8448", "reconnects": 5}
|
||||
"enabled": false, // starts SessionManager service: <true|false>
|
||||
"rals_conns": [
|
||||
{"address": "*internal"} // address where to reach the Rater <""|*internal|127.0.0.1:2013>
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <*internal|x.y.z.y:1234>
|
||||
],
|
||||
"create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
"debit_interval": "10s", // interval to perform debits on.
|
||||
"min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
"max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
"evapi_conns":[ // instantiate connections to multiple Kamailio servers
|
||||
{"address": "127.0.0.1:8448", "reconnects": 5}
|
||||
],
|
||||
},
|
||||
|
||||
@@ -251,8 +271,12 @@ const CGRATES_CFG_JSON = `
|
||||
"sm_opensips": {
|
||||
"enabled": false, // starts SessionManager service: <true|false>
|
||||
"listen_udp": "127.0.0.1:2020", // address where to listen for datagram events coming from OpenSIPS
|
||||
"rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
"cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
|
||||
"rals_conns": [
|
||||
{"address": "*internal"} // address where to reach the Rater <""|*internal|127.0.0.1:2013>
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <*internal|x.y.z.y:1234>
|
||||
],
|
||||
"reconnects": 5, // number of reconnects if connection is lost
|
||||
"create_cdr": false, // create CDR out of events and sends it to CDRS component
|
||||
"debit_interval": "10s", // interval to perform debits on.
|
||||
@@ -267,8 +291,10 @@ const CGRATES_CFG_JSON = `
|
||||
"enabled": false, // enables the diameter agent: <true|false>
|
||||
"listen": "127.0.0.1:3868", // address where to listen for diameter requests <x.y.z.y:1234>
|
||||
"dictionaries_dir": "/usr/share/cgrates/diameter/dict/", // path towards directory holding additional dictionaries to load
|
||||
"sm_generic": "internal", // connection towards SMG component for session management
|
||||
"pubsubs": "", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
|
||||
"sm_generic_conns": [
|
||||
{"address": "*internal"} // connection towards SMG component for session management
|
||||
],
|
||||
"pubsubs_conns": [], // address where to reach the pubusb service, empty to disable pubsub functionality: <""|*internal|x.y.z.y:1234>
|
||||
"create_cdr": true, // create CDR out of CCR terminate and send it to SMG component
|
||||
"debit_interval": "5m", // interval for CCR updates
|
||||
"timezone": "", // timezone for timestamps where not specified, empty for general defaults <""|UTC|Local|$IANA_TZ_DB>
|
||||
@@ -335,7 +361,7 @@ const CGRATES_CFG_JSON = `
|
||||
"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
|
||||
"auth_password": "CGRateS.org", // authenticate to email server with this password
|
||||
"from_address": "cgr-mailer@localhost.localdomain" // from address used when sending emails out
|
||||
},
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ const (
|
||||
DATADB_JSN = "data_db"
|
||||
STORDB_JSN = "stor_db"
|
||||
BALANCER_JSN = "balancer"
|
||||
RATER_JSN = "rater"
|
||||
RALS_JSN = "rals"
|
||||
SCHEDULER_JSN = "scheduler"
|
||||
CDRS_JSN = "cdrs"
|
||||
MEDIATOR_JSN = "mediator"
|
||||
@@ -128,12 +128,12 @@ func (self CgrJsonCfg) BalancerJsonCfg() (*BalancerJsonCfg, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (self CgrJsonCfg) RaterJsonCfg() (*RaterJsonCfg, error) {
|
||||
rawCfg, hasKey := self[RATER_JSN]
|
||||
func (self CgrJsonCfg) RalsJsonCfg() (*RalsJsonCfg, error) {
|
||||
rawCfg, hasKey := self[RALS_JSN]
|
||||
if !hasKey {
|
||||
return nil, nil
|
||||
}
|
||||
cfg := new(RaterJsonCfg)
|
||||
cfg := new(RalsJsonCfg)
|
||||
if err := json.Unmarshal(*rawCfg, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -188,12 +188,12 @@ func (self CgrJsonCfg) CdreJsonCfgs() (map[string]*CdreJsonCfg, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (self CgrJsonCfg) CdrcJsonCfg() (map[string]*CdrcJsonCfg, error) {
|
||||
func (self CgrJsonCfg) CdrcJsonCfg() ([]*CdrcJsonCfg, error) {
|
||||
rawCfg, hasKey := self[CDRC_JSN]
|
||||
if !hasKey {
|
||||
return nil, nil
|
||||
}
|
||||
cfg := make(map[string]*CdrcJsonCfg)
|
||||
cfg := make([]*CdrcJsonCfg, 0)
|
||||
if err := json.Unmarshal(*rawCfg, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -44,14 +44,13 @@ func TestDfGeneralJsonCfg(t *testing.T) {
|
||||
Dbdata_encoding: utils.StringPointer("msgpack"),
|
||||
Tpexport_dir: utils.StringPointer("/var/log/cgrates/tpe"),
|
||||
Http_failed_dir: utils.StringPointer("/var/log/cgrates/http_failed"),
|
||||
Default_reqtype: utils.StringPointer(utils.META_RATED),
|
||||
Default_request_type: utils.StringPointer(utils.META_RATED),
|
||||
Default_category: utils.StringPointer("call"),
|
||||
Default_tenant: utils.StringPointer("cgrates.org"),
|
||||
Default_subject: utils.StringPointer("cgrates"),
|
||||
Default_timezone: utils.StringPointer("Local"),
|
||||
Connect_attempts: utils.IntPointer(3),
|
||||
Reconnects: utils.IntPointer(-1),
|
||||
Response_cache_ttl: utils.StringPointer("3s"),
|
||||
Response_cache_ttl: utils.StringPointer("0s"),
|
||||
Internal_ttl: utils.StringPointer("2m")}
|
||||
if gCfg, err := dfCgrJsonCfg.GeneralJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
@@ -74,12 +73,12 @@ func TestDfListenJsonCfg(t *testing.T) {
|
||||
|
||||
func TestDfDbJsonCfg(t *testing.T) {
|
||||
eCfg := &DbJsonCfg{
|
||||
Db_type: utils.StringPointer("redis"),
|
||||
Db_host: utils.StringPointer("127.0.0.1"),
|
||||
Db_port: utils.IntPointer(6379),
|
||||
Db_name: utils.StringPointer("10"),
|
||||
Db_user: utils.StringPointer(""),
|
||||
Db_passwd: utils.StringPointer(""),
|
||||
Db_type: utils.StringPointer("redis"),
|
||||
Db_host: utils.StringPointer("127.0.0.1"),
|
||||
Db_port: utils.IntPointer(6379),
|
||||
Db_name: utils.StringPointer("10"),
|
||||
Db_user: utils.StringPointer(""),
|
||||
Db_password: utils.StringPointer(""),
|
||||
}
|
||||
if cfg, err := dfCgrJsonCfg.DbJsonCfg(TPDB_JSN); err != nil {
|
||||
t.Error(err)
|
||||
@@ -92,7 +91,7 @@ func TestDfDbJsonCfg(t *testing.T) {
|
||||
Db_port: utils.IntPointer(6379),
|
||||
Db_name: utils.StringPointer("11"),
|
||||
Db_user: utils.StringPointer(""),
|
||||
Db_passwd: utils.StringPointer(""),
|
||||
Db_password: utils.StringPointer(""),
|
||||
Load_history_size: utils.IntPointer(10),
|
||||
}
|
||||
if cfg, err := dfCgrJsonCfg.DbJsonCfg(DATADB_JSN); err != nil {
|
||||
@@ -106,7 +105,7 @@ func TestDfDbJsonCfg(t *testing.T) {
|
||||
Db_port: utils.IntPointer(3306),
|
||||
Db_name: utils.StringPointer("cgrates"),
|
||||
Db_user: utils.StringPointer("cgrates"),
|
||||
Db_passwd: utils.StringPointer("CGRateS.org"),
|
||||
Db_password: utils.StringPointer("CGRateS.org"),
|
||||
Max_open_conns: utils.IntPointer(100),
|
||||
Max_idle_conns: utils.IntPointer(10),
|
||||
Cdrs_indexes: utils.StringSlicePointer([]string{}),
|
||||
@@ -127,10 +126,11 @@ func TestDfBalancerJsonCfg(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDfRaterJsonCfg(t *testing.T) {
|
||||
eCfg := &RaterJsonCfg{Enabled: utils.BoolPointer(false), Balancer: utils.StringPointer(""), Cdrstats: utils.StringPointer(""),
|
||||
Historys: utils.StringPointer(""), Pubsubs: utils.StringPointer(""), Users: utils.StringPointer(""), Aliases: utils.StringPointer(""), Rp_subject_prefix_matching: utils.BoolPointer(false)}
|
||||
if cfg, err := dfCgrJsonCfg.RaterJsonCfg(); err != nil {
|
||||
func TestDfRalsJsonCfg(t *testing.T) {
|
||||
eCfg := &RalsJsonCfg{Enabled: utils.BoolPointer(false), Balancer: utils.StringPointer(""), Cdrstats_conns: &[]*HaPoolJsonCfg{},
|
||||
Historys_conns: &[]*HaPoolJsonCfg{}, Pubsubs_conns: &[]*HaPoolJsonCfg{}, Users_conns: &[]*HaPoolJsonCfg{}, Aliases_conns: &[]*HaPoolJsonCfg{},
|
||||
Rp_subject_prefix_matching: utils.BoolPointer(false), Lcr_subject_prefix_matching: utils.BoolPointer(false)}
|
||||
if cfg, err := dfCgrJsonCfg.RalsJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eCfg, cfg) {
|
||||
t.Errorf("Received: %+v", cfg)
|
||||
@@ -148,14 +148,17 @@ func TestDfSchedulerJsonCfg(t *testing.T) {
|
||||
|
||||
func TestDfCdrsJsonCfg(t *testing.T) {
|
||||
eCfg := &CdrsJsonCfg{
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Extra_fields: utils.StringSlicePointer([]string{}),
|
||||
Store_cdrs: utils.BoolPointer(true),
|
||||
Rater: utils.StringPointer("internal"),
|
||||
Pubsubs: utils.StringPointer(""),
|
||||
Users: utils.StringPointer(""),
|
||||
Aliases: utils.StringPointer(""),
|
||||
Cdrstats: utils.StringPointer(""),
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Extra_fields: utils.StringSlicePointer([]string{}),
|
||||
Store_cdrs: utils.BoolPointer(true),
|
||||
Rals_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer("*internal"),
|
||||
}},
|
||||
Pubsubs_conns: &[]*HaPoolJsonCfg{},
|
||||
Users_conns: &[]*HaPoolJsonCfg{},
|
||||
Aliases_conns: &[]*HaPoolJsonCfg{},
|
||||
Cdrstats_conns: &[]*HaPoolJsonCfg{},
|
||||
Cdr_replication: &[]*CdrReplicationJsonCfg{},
|
||||
}
|
||||
if cfg, err := dfCgrJsonCfg.CdrsJsonCfg(); err != nil {
|
||||
@@ -299,11 +302,14 @@ func TestDfCdrcJsonCfg(t *testing.T) {
|
||||
&CdrFieldJsonCfg{Tag: utils.StringPointer("Usage"), Field_id: utils.StringPointer(utils.USAGE), Type: utils.StringPointer(utils.META_COMPOSED),
|
||||
Value: utils.StringPointer("13"), Mandatory: utils.BoolPointer(true)},
|
||||
}
|
||||
eCfg := map[string]*CdrcJsonCfg{
|
||||
"*default": &CdrcJsonCfg{
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Dry_run: utils.BoolPointer(false),
|
||||
Cdrs: utils.StringPointer("internal"),
|
||||
eCfg := []*CdrcJsonCfg{
|
||||
&CdrcJsonCfg{
|
||||
Id: utils.StringPointer(utils.META_DEFAULT),
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Dry_run: utils.BoolPointer(false),
|
||||
Cdrs_conns: &[]*HaPoolJsonCfg{&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Cdr_format: utils.StringPointer("csv"),
|
||||
Field_separator: utils.StringPointer(","),
|
||||
Timezone: utils.StringPointer(""),
|
||||
@@ -325,19 +331,26 @@ func TestDfCdrcJsonCfg(t *testing.T) {
|
||||
if cfg, err := dfCgrJsonCfg.CdrcJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eCfg, cfg) {
|
||||
t.Error("Received: ", cfg["*default"])
|
||||
t.Errorf("Expecting: \n%s\n, received: \n%s\n: ", utils.ToIJSON(eCfg), utils.ToIJSON(cfg))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSmGenericJsonCfg(t *testing.T) {
|
||||
eCfg := &SmGenericJsonCfg{
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Listen_bijson: utils.StringPointer("127.0.0.1:2014"),
|
||||
Rater: utils.StringPointer("internal"),
|
||||
Cdrs: utils.StringPointer("internal"),
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Listen_bijson: utils.StringPointer("127.0.0.1:2014"),
|
||||
Rals_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Cdrs_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Debit_interval: utils.StringPointer("0s"),
|
||||
Min_call_duration: utils.StringPointer("0s"),
|
||||
Max_call_duration: utils.StringPointer("3h"),
|
||||
Session_ttl: utils.StringPointer("0s"),
|
||||
}
|
||||
if cfg, err := dfCgrJsonCfg.SmGenericJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
@@ -348,9 +361,15 @@ func TestSmGenericJsonCfg(t *testing.T) {
|
||||
|
||||
func TestSmFsJsonCfg(t *testing.T) {
|
||||
eCfg := &SmFsJsonCfg{
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Rater: utils.StringPointer("internal"),
|
||||
Cdrs: utils.StringPointer("internal"),
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Rals_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Cdrs_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Create_cdr: utils.BoolPointer(false),
|
||||
Extra_fields: utils.StringSlicePointer([]string{}),
|
||||
Debit_interval: utils.StringPointer("10s"),
|
||||
@@ -363,9 +382,9 @@ func TestSmFsJsonCfg(t *testing.T) {
|
||||
Subscribe_park: utils.BoolPointer(true),
|
||||
Channel_sync_interval: utils.StringPointer("5m"),
|
||||
Max_wait_connection: utils.StringPointer("2s"),
|
||||
Connections: &[]*FsConnJsonCfg{
|
||||
Event_socket_conns: &[]*FsConnJsonCfg{
|
||||
&FsConnJsonCfg{
|
||||
Server: utils.StringPointer("127.0.0.1:8021"),
|
||||
Address: utils.StringPointer("127.0.0.1:8021"),
|
||||
Password: utils.StringPointer("ClueCon"),
|
||||
Reconnects: utils.IntPointer(5),
|
||||
}},
|
||||
@@ -379,16 +398,22 @@ func TestSmFsJsonCfg(t *testing.T) {
|
||||
|
||||
func TestSmKamJsonCfg(t *testing.T) {
|
||||
eCfg := &SmKamJsonCfg{
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Rater: utils.StringPointer("internal"),
|
||||
Cdrs: utils.StringPointer("internal"),
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Rals_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Cdrs_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Create_cdr: utils.BoolPointer(false),
|
||||
Debit_interval: utils.StringPointer("10s"),
|
||||
Min_call_duration: utils.StringPointer("0s"),
|
||||
Max_call_duration: utils.StringPointer("3h"),
|
||||
Connections: &[]*KamConnJsonCfg{
|
||||
Evapi_conns: &[]*KamConnJsonCfg{
|
||||
&KamConnJsonCfg{
|
||||
Evapi_addr: utils.StringPointer("127.0.0.1:8448"),
|
||||
Address: utils.StringPointer("127.0.0.1:8448"),
|
||||
Reconnects: utils.IntPointer(5),
|
||||
},
|
||||
},
|
||||
@@ -402,10 +427,16 @@ func TestSmKamJsonCfg(t *testing.T) {
|
||||
|
||||
func TestSmOsipsJsonCfg(t *testing.T) {
|
||||
eCfg := &SmOsipsJsonCfg{
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Listen_udp: utils.StringPointer("127.0.0.1:2020"),
|
||||
Rater: utils.StringPointer("internal"),
|
||||
Cdrs: utils.StringPointer("internal"),
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Listen_udp: utils.StringPointer("127.0.0.1:2020"),
|
||||
Rals_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Cdrs_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Create_cdr: utils.BoolPointer(false),
|
||||
Debit_interval: utils.StringPointer("10s"),
|
||||
Min_call_duration: utils.StringPointer("0s"),
|
||||
@@ -425,16 +456,19 @@ func TestDiameterAgentJsonCfg(t *testing.T) {
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Listen: utils.StringPointer("127.0.0.1:3868"),
|
||||
Dictionaries_dir: utils.StringPointer("/usr/share/cgrates/diameter/dict/"),
|
||||
Sm_generic: utils.StringPointer("internal"),
|
||||
Pubsubs: utils.StringPointer(""),
|
||||
Create_cdr: utils.BoolPointer(true),
|
||||
Debit_interval: utils.StringPointer("5m"),
|
||||
Timezone: utils.StringPointer(""),
|
||||
Dialect: utils.StringPointer("huawei"),
|
||||
Origin_host: utils.StringPointer("CGR-DA"),
|
||||
Origin_realm: utils.StringPointer("cgrates.org"),
|
||||
Vendor_id: utils.IntPointer(0),
|
||||
Product_name: utils.StringPointer("CGRateS"),
|
||||
Sm_generic_conns: &[]*HaPoolJsonCfg{
|
||||
&HaPoolJsonCfg{
|
||||
Address: utils.StringPointer(utils.MetaInternal),
|
||||
}},
|
||||
Pubsubs_conns: &[]*HaPoolJsonCfg{},
|
||||
Create_cdr: utils.BoolPointer(true),
|
||||
Debit_interval: utils.StringPointer("5m"),
|
||||
Timezone: utils.StringPointer(""),
|
||||
Dialect: utils.StringPointer("huawei"),
|
||||
Origin_host: utils.StringPointer("CGR-DA"),
|
||||
Origin_realm: utils.StringPointer("cgrates.org"),
|
||||
Vendor_id: utils.IntPointer(0),
|
||||
Product_name: utils.StringPointer("CGRateS"),
|
||||
Request_processors: &[]*DARequestProcessorJsnCfg{
|
||||
&DARequestProcessorJsnCfg{
|
||||
Id: utils.StringPointer("*default"),
|
||||
@@ -536,10 +570,10 @@ func TestDfUserServJsonCfg(t *testing.T) {
|
||||
|
||||
func TestDfMailerJsonCfg(t *testing.T) {
|
||||
eCfg := &MailerJsonCfg{
|
||||
Server: utils.StringPointer("localhost"),
|
||||
Auth_user: utils.StringPointer("cgrates"),
|
||||
Auth_passwd: utils.StringPointer("CGRateS.org"),
|
||||
From_address: utils.StringPointer("cgr-mailer@localhost.localdomain"),
|
||||
Server: utils.StringPointer("localhost"),
|
||||
Auth_user: utils.StringPointer("cgrates"),
|
||||
Auth_password: utils.StringPointer("CGRateS.org"),
|
||||
From_address: utils.StringPointer("cgr-mailer@localhost.localdomain"),
|
||||
}
|
||||
if cfg, err := dfCgrJsonCfg.MailerJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
@@ -589,25 +623,27 @@ func TestNewCgrJsonCfgFromFile(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
eCfg := &GeneralJsonCfg{Default_reqtype: utils.StringPointer(utils.META_PSEUDOPREPAID)}
|
||||
eCfg := &GeneralJsonCfg{Default_request_type: utils.StringPointer(utils.META_PSEUDOPREPAID)}
|
||||
if gCfg, err := cgrJsonCfg.GeneralJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eCfg, gCfg) {
|
||||
t.Error("Received: ", gCfg)
|
||||
t.Errorf("Expecting: %+v, received: ", eCfg, gCfg)
|
||||
}
|
||||
cdrFields := []*CdrFieldJsonCfg{
|
||||
&CdrFieldJsonCfg{Field_id: utils.StringPointer(utils.TOR), Value: utils.StringPointer("~7:s/^(voice|data|sms|mms|generic)$/*$1/")},
|
||||
&CdrFieldJsonCfg{Field_id: utils.StringPointer(utils.ANSWER_TIME), Value: utils.StringPointer("1")},
|
||||
&CdrFieldJsonCfg{Field_id: utils.StringPointer(utils.USAGE), Value: utils.StringPointer(`~9:s/^(\d+)$/${1}s/`)},
|
||||
}
|
||||
eCfgCdrc := map[string]*CdrcJsonCfg{
|
||||
"CDRC-CSV1": &CdrcJsonCfg{
|
||||
eCfgCdrc := []*CdrcJsonCfg{
|
||||
&CdrcJsonCfg{
|
||||
Id: utils.StringPointer("CDRC-CSV1"),
|
||||
Enabled: utils.BoolPointer(true),
|
||||
Cdr_in_dir: utils.StringPointer("/tmp/cgrates/cdrc1/in"),
|
||||
Cdr_out_dir: utils.StringPointer("/tmp/cgrates/cdrc1/out"),
|
||||
Cdr_source_id: utils.StringPointer("csv1"),
|
||||
},
|
||||
"CDRC-CSV2": &CdrcJsonCfg{
|
||||
&CdrcJsonCfg{
|
||||
Id: utils.StringPointer("CDRC-CSV2"),
|
||||
Enabled: utils.BoolPointer(true),
|
||||
Data_usage_multiply_factor: utils.Float64Pointer(0.000976563),
|
||||
Run_delay: utils.IntPointer(1),
|
||||
@@ -620,18 +656,18 @@ func TestNewCgrJsonCfgFromFile(t *testing.T) {
|
||||
if cfg, err := cgrJsonCfg.CdrcJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eCfgCdrc, cfg) {
|
||||
t.Error("Received: ", utils.ToIJSON(cfg["CDRC-CSV2"]))
|
||||
t.Errorf("Expecting:\n %+v\n received:\n %+v\n", utils.ToIJSON(eCfgCdrc), utils.ToIJSON(cfg))
|
||||
}
|
||||
eCfgSmFs := &SmFsJsonCfg{
|
||||
Enabled: utils.BoolPointer(true),
|
||||
Connections: &[]*FsConnJsonCfg{
|
||||
Event_socket_conns: &[]*FsConnJsonCfg{
|
||||
&FsConnJsonCfg{
|
||||
Server: utils.StringPointer("1.2.3.4:8021"),
|
||||
Address: utils.StringPointer("1.2.3.4:8021"),
|
||||
Password: utils.StringPointer("ClueCon"),
|
||||
Reconnects: utils.IntPointer(5),
|
||||
},
|
||||
&FsConnJsonCfg{
|
||||
Server: utils.StringPointer("2.3.4.5:8021"),
|
||||
Address: utils.StringPointer("2.3.4.5:8021"),
|
||||
Password: utils.StringPointer("ClueCon"),
|
||||
Reconnects: utils.IntPointer(5),
|
||||
},
|
||||
|
||||
@@ -39,18 +39,18 @@ func TestLoadCgrCfgWithDefaults(t *testing.T) {
|
||||
{
|
||||
"sm_freeswitch": {
|
||||
"enabled": true, // starts SessionManager service: <true|false>
|
||||
"connections":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
{"server": "1.2.3.4:8021", "password": "ClueCon", "reconnects": 3},
|
||||
{"server": "1.2.3.5:8021", "password": "ClueCon", "reconnects": 5}
|
||||
"event_socket_conns":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
{"address": "1.2.3.4:8021", "password": "ClueCon", "reconnects": 3},
|
||||
{"address": "1.2.3.5:8021", "password": "ClueCon", "reconnects": 5}
|
||||
],
|
||||
},
|
||||
|
||||
}`
|
||||
eCgrCfg, _ := NewDefaultCGRConfig()
|
||||
eCgrCfg.SmFsConfig.Enabled = true
|
||||
eCgrCfg.SmFsConfig.Connections = []*FsConnConfig{
|
||||
&FsConnConfig{Server: "1.2.3.4:8021", Password: "ClueCon", Reconnects: 3},
|
||||
&FsConnConfig{Server: "1.2.3.5:8021", Password: "ClueCon", Reconnects: 5},
|
||||
eCgrCfg.SmFsConfig.EventSocketConns = []*FsConnConfig{
|
||||
&FsConnConfig{Address: "1.2.3.4:8021", Password: "ClueCon", Reconnects: 3},
|
||||
&FsConnConfig{Address: "1.2.3.5:8021", Password: "ClueCon", Reconnects: 5},
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJsonStringWithDefaults(JSN_CFG); err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -32,12 +32,13 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
eCgrCfg, _ := NewDefaultCGRConfig()
|
||||
eCgrCfg.CdrcProfiles = make(map[string]map[string]*CdrcConfig)
|
||||
eCgrCfg.CdrcProfiles = make(map[string][]*CdrcConfig)
|
||||
// Default instance first
|
||||
eCgrCfg.CdrcProfiles["/var/log/cgrates/cdrc/in"] = map[string]*CdrcConfig{
|
||||
"*default": &CdrcConfig{
|
||||
eCgrCfg.CdrcProfiles["/var/log/cgrates/cdrc/in"] = []*CdrcConfig{
|
||||
&CdrcConfig{
|
||||
ID: utils.META_DEFAULT,
|
||||
Enabled: false,
|
||||
Cdrs: "internal",
|
||||
CdrsConns: []*HaPoolConfig{&HaPoolConfig{Address: utils.MetaInternal}},
|
||||
CdrFormat: "csv",
|
||||
FieldSeparator: ',',
|
||||
DataUsageMultiplyFactor: 1024,
|
||||
@@ -79,10 +80,11 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) {
|
||||
TrailerFields: make([]*CfgCdrField, 0),
|
||||
},
|
||||
}
|
||||
eCgrCfg.CdrcProfiles["/tmp/cgrates/cdrc1/in"] = map[string]*CdrcConfig{
|
||||
"CDRC-CSV1": &CdrcConfig{
|
||||
eCgrCfg.CdrcProfiles["/tmp/cgrates/cdrc1/in"] = []*CdrcConfig{
|
||||
&CdrcConfig{
|
||||
ID: "CDRC-CSV1",
|
||||
Enabled: true,
|
||||
Cdrs: "internal",
|
||||
CdrsConns: []*HaPoolConfig{&HaPoolConfig{Address: utils.MetaInternal}},
|
||||
CdrFormat: "csv",
|
||||
FieldSeparator: ',',
|
||||
DataUsageMultiplyFactor: 1024,
|
||||
@@ -122,14 +124,15 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) {
|
||||
TrailerFields: make([]*CfgCdrField, 0),
|
||||
},
|
||||
}
|
||||
eCgrCfg.CdrcProfiles["/tmp/cgrates/cdrc2/in"] = map[string]*CdrcConfig{
|
||||
"CDRC-CSV2": &CdrcConfig{
|
||||
eCgrCfg.CdrcProfiles["/tmp/cgrates/cdrc2/in"] = []*CdrcConfig{
|
||||
&CdrcConfig{
|
||||
ID: "CDRC-CSV2",
|
||||
Enabled: true,
|
||||
Cdrs: "internal",
|
||||
CdrsConns: []*HaPoolConfig{&HaPoolConfig{Address: utils.MetaInternal}},
|
||||
CdrFormat: "csv",
|
||||
FieldSeparator: ',',
|
||||
DataUsageMultiplyFactor: 0.000976563,
|
||||
RunDelay: 0,
|
||||
RunDelay: 1000000000,
|
||||
MaxOpenFiles: 1024,
|
||||
CdrInDir: "/tmp/cgrates/cdrc2/in",
|
||||
CdrOutDir: "/tmp/cgrates/cdrc2/out",
|
||||
@@ -137,18 +140,21 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) {
|
||||
CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP),
|
||||
HeaderFields: make([]*CfgCdrField, 0),
|
||||
ContentFields: []*CfgCdrField{
|
||||
&CfgCdrField{Tag: "", Type: "", FieldId: utils.TOR, Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|generic)$/*$1/", utils.INFIELD_SEP),
|
||||
&CfgCdrField{FieldId: utils.TOR, Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false},
|
||||
&CfgCdrField{Tag: "", Type: "", FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP),
|
||||
&CfgCdrField{Tag: "", Type: "", FieldId: utils.ANSWER_TIME, Value: utils.ParseRSRFieldsMustCompile("1", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false},
|
||||
&CfgCdrField{FieldId: utils.USAGE, Value: utils.ParseRSRFieldsMustCompile("~9:s/^(\\d+)$/${1}s/", utils.INFIELD_SEP),
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false},
|
||||
},
|
||||
TrailerFields: make([]*CfgCdrField, 0),
|
||||
},
|
||||
}
|
||||
eCgrCfg.CdrcProfiles["/tmp/cgrates/cdrc3/in"] = map[string]*CdrcConfig{
|
||||
"CDRC-CSV3": &CdrcConfig{
|
||||
eCgrCfg.CdrcProfiles["/tmp/cgrates/cdrc3/in"] = []*CdrcConfig{
|
||||
&CdrcConfig{
|
||||
ID: "CDRC-CSV3",
|
||||
Enabled: true,
|
||||
Cdrs: "internal",
|
||||
CdrsConns: []*HaPoolConfig{&HaPoolConfig{Address: utils.MetaInternal}},
|
||||
CdrFormat: "csv",
|
||||
FieldSeparator: ',',
|
||||
DataUsageMultiplyFactor: 1024,
|
||||
@@ -189,6 +195,6 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) {
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(eCgrCfg.CdrcProfiles, cgrCfg.CdrcProfiles) {
|
||||
t.Errorf("Expected: %+v, received: %+v", eCgrCfg.CdrcProfiles, cgrCfg.CdrcProfiles)
|
||||
t.Errorf("Expected: \n%s\n, received: \n%s\n", utils.ToJSON(eCgrCfg.CdrcProfiles), utils.ToJSON(cgrCfg.CdrcProfiles))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ type DiameterAgentCfg struct {
|
||||
Enabled bool // enables the diameter agent: <true|false>
|
||||
Listen string // address where to listen for diameter requests <x.y.z.y:1234>
|
||||
DictionariesDir string
|
||||
SMGeneric string // connection towards SMG component
|
||||
PubSubS string // connection towards pubsubs
|
||||
SMGenericConns []*HaPoolConfig // connections towards SMG component
|
||||
PubSubConns []*HaPoolConfig // connection towards pubsubs
|
||||
CreateCDR bool
|
||||
DebitInterval time.Duration
|
||||
Timezone string // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
@@ -54,11 +54,19 @@ func (self *DiameterAgentCfg) loadFromJsonCfg(jsnCfg *DiameterAgentJsonCfg) erro
|
||||
if jsnCfg.Dictionaries_dir != nil {
|
||||
self.DictionariesDir = *jsnCfg.Dictionaries_dir
|
||||
}
|
||||
if jsnCfg.Sm_generic != nil {
|
||||
self.SMGeneric = *jsnCfg.Sm_generic
|
||||
if jsnCfg.Sm_generic_conns != nil {
|
||||
self.SMGenericConns = make([]*HaPoolConfig, len(*jsnCfg.Sm_generic_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Sm_generic_conns {
|
||||
self.SMGenericConns[idx] = NewDfltHaPoolConfig()
|
||||
self.SMGenericConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Pubsubs != nil {
|
||||
self.PubSubS = *jsnCfg.Pubsubs
|
||||
if jsnCfg.Pubsubs_conns != nil {
|
||||
self.PubSubConns = make([]*HaPoolConfig, len(*jsnCfg.Pubsubs_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Pubsubs_conns {
|
||||
self.PubSubConns[idx] = NewDfltHaPoolConfig()
|
||||
self.PubSubConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Create_cdr != nil {
|
||||
self.CreateCDR = *jsnCfg.Create_cdr
|
||||
|
||||
@@ -26,12 +26,12 @@ import (
|
||||
|
||||
type CdrReplicationCfg struct {
|
||||
Transport string
|
||||
Server string
|
||||
Address string
|
||||
Synchronous bool
|
||||
Attempts int // Number of attempts if not success
|
||||
CdrFilter utils.RSRFields // Only replicate if the filters here are matching
|
||||
}
|
||||
|
||||
func (rplCfg CdrReplicationCfg) FallbackFileName() string {
|
||||
return fmt.Sprintf("cdr_%s_%s_%s.form", rplCfg.Transport, url.QueryEscape(rplCfg.Server), utils.GenUUID())
|
||||
return fmt.Sprintf("cdr_%s_%s_%s.form", rplCfg.Transport, url.QueryEscape(rplCfg.Address), utils.GenUUID())
|
||||
}
|
||||
|
||||
@@ -25,10 +25,9 @@ type GeneralJsonCfg struct {
|
||||
Dbdata_encoding *string
|
||||
Tpexport_dir *string
|
||||
Http_failed_dir *string
|
||||
Default_reqtype *string
|
||||
Default_request_type *string
|
||||
Default_category *string
|
||||
Default_tenant *string
|
||||
Default_subject *string
|
||||
Default_timezone *string
|
||||
Connect_attempts *int
|
||||
Reconnects *int
|
||||
@@ -50,7 +49,7 @@ type DbJsonCfg struct {
|
||||
Db_port *int
|
||||
Db_name *string
|
||||
Db_user *string
|
||||
Db_passwd *string
|
||||
Db_password *string
|
||||
Max_open_conns *int // Used only in case of storDb
|
||||
Max_idle_conns *int
|
||||
Load_history_size *int // Used in case of dataDb to limit the length of the loads history
|
||||
@@ -63,15 +62,16 @@ type BalancerJsonCfg struct {
|
||||
}
|
||||
|
||||
// Rater config section
|
||||
type RaterJsonCfg struct {
|
||||
Enabled *bool
|
||||
Balancer *string
|
||||
Cdrstats *string
|
||||
Historys *string
|
||||
Pubsubs *string
|
||||
Aliases *string
|
||||
Users *string
|
||||
Rp_subject_prefix_matching *bool
|
||||
type RalsJsonCfg struct {
|
||||
Enabled *bool
|
||||
Balancer *string
|
||||
Cdrstats_conns *[]*HaPoolJsonCfg
|
||||
Historys_conns *[]*HaPoolJsonCfg
|
||||
Pubsubs_conns *[]*HaPoolJsonCfg
|
||||
Aliases_conns *[]*HaPoolJsonCfg
|
||||
Users_conns *[]*HaPoolJsonCfg
|
||||
Rp_subject_prefix_matching *bool
|
||||
Lcr_subject_prefix_matching *bool
|
||||
}
|
||||
|
||||
// Scheduler config section
|
||||
@@ -84,17 +84,17 @@ type CdrsJsonCfg struct {
|
||||
Enabled *bool
|
||||
Extra_fields *[]string
|
||||
Store_cdrs *bool
|
||||
Rater *string
|
||||
Pubsubs *string
|
||||
Users *string
|
||||
Aliases *string
|
||||
Cdrstats *string
|
||||
Rals_conns *[]*HaPoolJsonCfg
|
||||
Pubsubs_conns *[]*HaPoolJsonCfg
|
||||
Users_conns *[]*HaPoolJsonCfg
|
||||
Aliases_conns *[]*HaPoolJsonCfg
|
||||
Cdrstats_conns *[]*HaPoolJsonCfg
|
||||
Cdr_replication *[]*CdrReplicationJsonCfg
|
||||
}
|
||||
|
||||
type CdrReplicationJsonCfg struct {
|
||||
Transport *string
|
||||
Server *string
|
||||
Address *string
|
||||
Synchronous *bool
|
||||
Attempts *int
|
||||
Cdr_filter *string
|
||||
@@ -143,9 +143,10 @@ type CdreJsonCfg struct {
|
||||
|
||||
// Cdrc config section
|
||||
type CdrcJsonCfg struct {
|
||||
Id *string
|
||||
Enabled *bool
|
||||
Dry_run *bool
|
||||
Cdrs *string
|
||||
Cdrs_conns *[]*HaPoolJsonCfg
|
||||
Cdr_format *string
|
||||
Field_separator *string
|
||||
Timezone *string
|
||||
@@ -166,20 +167,23 @@ type CdrcJsonCfg struct {
|
||||
|
||||
// SM-Generic config section
|
||||
type SmGenericJsonCfg struct {
|
||||
Enabled *bool
|
||||
Listen_bijson *string
|
||||
Rater *string
|
||||
Cdrs *string
|
||||
Debit_interval *string
|
||||
Min_call_duration *string
|
||||
Max_call_duration *string
|
||||
Enabled *bool
|
||||
Listen_bijson *string
|
||||
Rals_conns *[]*HaPoolJsonCfg
|
||||
Cdrs_conns *[]*HaPoolJsonCfg
|
||||
Debit_interval *string
|
||||
Min_call_duration *string
|
||||
Max_call_duration *string
|
||||
Session_ttl *string
|
||||
Session_ttl_last_used *string
|
||||
Session_ttl_usage *string
|
||||
}
|
||||
|
||||
// SM-FreeSWITCH config section
|
||||
type SmFsJsonCfg struct {
|
||||
Enabled *bool
|
||||
Rater *string
|
||||
Cdrs *string
|
||||
Rals_conns *[]*HaPoolJsonCfg
|
||||
Cdrs_conns *[]*HaPoolJsonCfg
|
||||
Create_cdr *bool
|
||||
Extra_fields *[]string
|
||||
Debit_interval *string
|
||||
@@ -192,12 +196,17 @@ type SmFsJsonCfg struct {
|
||||
Subscribe_park *bool
|
||||
Channel_sync_interval *string
|
||||
Max_wait_connection *string
|
||||
Connections *[]*FsConnJsonCfg
|
||||
Event_socket_conns *[]*FsConnJsonCfg
|
||||
}
|
||||
|
||||
// Represents one connection instance towards a rater/cdrs server
|
||||
type HaPoolJsonCfg struct {
|
||||
Address *string
|
||||
}
|
||||
|
||||
// Represents one connection instance towards FreeSWITCH
|
||||
type FsConnJsonCfg struct {
|
||||
Server *string
|
||||
Address *string
|
||||
Password *string
|
||||
Reconnects *int
|
||||
}
|
||||
@@ -205,18 +214,18 @@ type FsConnJsonCfg struct {
|
||||
// SM-Kamailio config section
|
||||
type SmKamJsonCfg struct {
|
||||
Enabled *bool
|
||||
Rater *string
|
||||
Cdrs *string
|
||||
Rals_conns *[]*HaPoolJsonCfg
|
||||
Cdrs_conns *[]*HaPoolJsonCfg
|
||||
Create_cdr *bool
|
||||
Debit_interval *string
|
||||
Min_call_duration *string
|
||||
Max_call_duration *string
|
||||
Connections *[]*KamConnJsonCfg
|
||||
Evapi_conns *[]*KamConnJsonCfg
|
||||
}
|
||||
|
||||
// Represents one connection instance towards Kamailio
|
||||
type KamConnJsonCfg struct {
|
||||
Evapi_addr *string
|
||||
Address *string
|
||||
Reconnects *int
|
||||
}
|
||||
|
||||
@@ -224,8 +233,8 @@ type KamConnJsonCfg struct {
|
||||
type SmOsipsJsonCfg struct {
|
||||
Enabled *bool
|
||||
Listen_udp *string
|
||||
Rater *string
|
||||
Cdrs *string
|
||||
Rals_conns *[]*HaPoolJsonCfg
|
||||
Cdrs_conns *[]*HaPoolJsonCfg
|
||||
Create_cdr *bool
|
||||
Debit_interval *string
|
||||
Min_call_duration *string
|
||||
@@ -242,11 +251,11 @@ type OsipsConnJsonCfg struct {
|
||||
|
||||
// DiameterAgent configuration
|
||||
type DiameterAgentJsonCfg struct {
|
||||
Enabled *bool // enables the diameter agent: <true|false>
|
||||
Listen *string // address where to listen for diameter requests <x.y.z.y:1234>
|
||||
Dictionaries_dir *string // path towards additional dictionaries
|
||||
Sm_generic *string // connection towards generic SM
|
||||
Pubsubs *string // connection towards pubsubs
|
||||
Enabled *bool // enables the diameter agent: <true|false>
|
||||
Listen *string // address where to listen for diameter requests <x.y.z.y:1234>
|
||||
Dictionaries_dir *string // path towards additional dictionaries
|
||||
Sm_generic_conns *[]*HaPoolJsonCfg // Connections towards generic SM
|
||||
Pubsubs_conns *[]*HaPoolJsonCfg // connection towards pubsubs
|
||||
Create_cdr *bool
|
||||
Debit_interval *string
|
||||
Timezone *string // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
@@ -296,10 +305,10 @@ type UserServJsonCfg struct {
|
||||
|
||||
// Mailer config section
|
||||
type MailerJsonCfg struct {
|
||||
Server *string
|
||||
Auth_user *string
|
||||
Auth_passwd *string
|
||||
From_address *string
|
||||
Server *string
|
||||
Auth_user *string
|
||||
Auth_password *string
|
||||
From_address *string
|
||||
}
|
||||
|
||||
// SureTax config section
|
||||
|
||||
@@ -35,8 +35,17 @@ func NewDfltHaPoolConfig() *HaPoolConfig {
|
||||
|
||||
// One connection to Rater
|
||||
type HaPoolConfig struct {
|
||||
Server string
|
||||
Timeout time.Duration
|
||||
Address string
|
||||
}
|
||||
|
||||
func (self *HaPoolConfig) loadFromJsonCfg(jsnCfg *HaPoolJsonCfg) error {
|
||||
if jsnCfg == nil {
|
||||
return nil
|
||||
}
|
||||
if jsnCfg.Address != nil {
|
||||
self.Address = *jsnCfg.Address
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the first cached default value for a SM-FreeSWITCH connection
|
||||
@@ -50,7 +59,7 @@ func NewDfltFsConnConfig() *FsConnConfig {
|
||||
|
||||
// One connection to FreeSWITCH server
|
||||
type FsConnConfig struct {
|
||||
Server string
|
||||
Address string
|
||||
Password string
|
||||
Reconnects int
|
||||
}
|
||||
@@ -59,8 +68,8 @@ func (self *FsConnConfig) loadFromJsonCfg(jsnCfg *FsConnJsonCfg) error {
|
||||
if jsnCfg == nil {
|
||||
return nil
|
||||
}
|
||||
if jsnCfg.Server != nil {
|
||||
self.Server = *jsnCfg.Server
|
||||
if jsnCfg.Address != nil {
|
||||
self.Address = *jsnCfg.Address
|
||||
}
|
||||
if jsnCfg.Password != nil {
|
||||
self.Password = *jsnCfg.Password
|
||||
@@ -72,13 +81,16 @@ func (self *FsConnConfig) loadFromJsonCfg(jsnCfg *FsConnJsonCfg) error {
|
||||
}
|
||||
|
||||
type SmGenericConfig struct {
|
||||
Enabled bool
|
||||
ListenBijson string
|
||||
HaRater []*HaPoolConfig
|
||||
HaCdrs []*HaPoolConfig
|
||||
DebitInterval time.Duration
|
||||
MinCallDuration time.Duration
|
||||
MaxCallDuration time.Duration
|
||||
Enabled bool
|
||||
ListenBijson string
|
||||
RALsConns []*HaPoolConfig
|
||||
CDRsConns []*HaPoolConfig
|
||||
DebitInterval time.Duration
|
||||
MinCallDuration time.Duration
|
||||
MaxCallDuration time.Duration
|
||||
SessionTTL time.Duration
|
||||
SessionTTLLastUsed *time.Duration
|
||||
SessionTTLUsage *time.Duration
|
||||
}
|
||||
|
||||
func (self *SmGenericConfig) loadFromJsonCfg(jsnCfg *SmGenericJsonCfg) error {
|
||||
@@ -92,11 +104,19 @@ func (self *SmGenericConfig) loadFromJsonCfg(jsnCfg *SmGenericJsonCfg) error {
|
||||
if jsnCfg.Listen_bijson != nil {
|
||||
self.ListenBijson = *jsnCfg.Listen_bijson
|
||||
}
|
||||
if jsnCfg.Rater != nil {
|
||||
self.HaRater = []*HaPoolConfig{&HaPoolConfig{Server: *jsnCfg.Rater, Timeout: time.Duration(1) * time.Second}}
|
||||
if jsnCfg.Rals_conns != nil {
|
||||
self.RALsConns = make([]*HaPoolConfig, len(*jsnCfg.Rals_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Rals_conns {
|
||||
self.RALsConns[idx] = NewDfltHaPoolConfig()
|
||||
self.RALsConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Cdrs != nil {
|
||||
self.HaCdrs = []*HaPoolConfig{&HaPoolConfig{Server: *jsnCfg.Cdrs, Timeout: time.Duration(1) * time.Second}}
|
||||
if jsnCfg.Cdrs_conns != nil {
|
||||
self.CDRsConns = make([]*HaPoolConfig, len(*jsnCfg.Cdrs_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Cdrs_conns {
|
||||
self.CDRsConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CDRsConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Debit_interval != nil {
|
||||
if self.DebitInterval, err = utils.ParseDurationWithSecs(*jsnCfg.Debit_interval); err != nil {
|
||||
@@ -113,13 +133,32 @@ func (self *SmGenericConfig) loadFromJsonCfg(jsnCfg *SmGenericJsonCfg) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Session_ttl != nil {
|
||||
if self.SessionTTL, err = utils.ParseDurationWithSecs(*jsnCfg.Session_ttl); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Session_ttl_last_used != nil {
|
||||
if sessionTTLLastUsed, err := utils.ParseDurationWithSecs(*jsnCfg.Session_ttl_last_used); err != nil {
|
||||
return err
|
||||
} else {
|
||||
self.SessionTTLLastUsed = &sessionTTLLastUsed
|
||||
}
|
||||
}
|
||||
if jsnCfg.Session_ttl_usage != nil {
|
||||
if sessionTTLUsage, err := utils.ParseDurationWithSecs(*jsnCfg.Session_ttl_usage); err != nil {
|
||||
return err
|
||||
} else {
|
||||
self.SessionTTLUsage = &sessionTTLUsage
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SmFsConfig struct {
|
||||
Enabled bool
|
||||
HaRater []*HaPoolConfig
|
||||
HaCdrs []*HaPoolConfig
|
||||
RALsConns []*HaPoolConfig
|
||||
CDRsConns []*HaPoolConfig
|
||||
CreateCdr bool
|
||||
ExtraFields []*utils.RSRField
|
||||
DebitInterval time.Duration
|
||||
@@ -132,7 +171,7 @@ type SmFsConfig struct {
|
||||
SubscribePark bool
|
||||
ChannelSyncInterval time.Duration
|
||||
MaxWaitConnection time.Duration
|
||||
Connections []*FsConnConfig
|
||||
EventSocketConns []*FsConnConfig
|
||||
}
|
||||
|
||||
func (self *SmFsConfig) loadFromJsonCfg(jsnCfg *SmFsJsonCfg) error {
|
||||
@@ -143,11 +182,19 @@ func (self *SmFsConfig) loadFromJsonCfg(jsnCfg *SmFsJsonCfg) error {
|
||||
if jsnCfg.Enabled != nil {
|
||||
self.Enabled = *jsnCfg.Enabled
|
||||
}
|
||||
if jsnCfg.Rater != nil {
|
||||
self.HaRater = []*HaPoolConfig{&HaPoolConfig{Server: *jsnCfg.Rater, Timeout: time.Duration(1) * time.Second}}
|
||||
if jsnCfg.Rals_conns != nil {
|
||||
self.RALsConns = make([]*HaPoolConfig, len(*jsnCfg.Rals_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Rals_conns {
|
||||
self.RALsConns[idx] = NewDfltHaPoolConfig()
|
||||
self.RALsConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Cdrs != nil {
|
||||
self.HaCdrs = []*HaPoolConfig{&HaPoolConfig{Server: *jsnCfg.Cdrs, Timeout: time.Duration(1) * time.Second}}
|
||||
if jsnCfg.Cdrs_conns != nil {
|
||||
self.CDRsConns = make([]*HaPoolConfig, len(*jsnCfg.Cdrs_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Cdrs_conns {
|
||||
self.CDRsConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CDRsConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Create_cdr != nil {
|
||||
self.CreateCdr = *jsnCfg.Create_cdr
|
||||
@@ -199,11 +246,11 @@ func (self *SmFsConfig) loadFromJsonCfg(jsnCfg *SmFsJsonCfg) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Connections != nil {
|
||||
self.Connections = make([]*FsConnConfig, len(*jsnCfg.Connections))
|
||||
for idx, jsnConnCfg := range *jsnCfg.Connections {
|
||||
self.Connections[idx] = NewDfltFsConnConfig()
|
||||
self.Connections[idx].loadFromJsonCfg(jsnConnCfg)
|
||||
if jsnCfg.Event_socket_conns != nil {
|
||||
self.EventSocketConns = make([]*FsConnConfig, len(*jsnCfg.Event_socket_conns))
|
||||
for idx, jsnConnCfg := range *jsnCfg.Event_socket_conns {
|
||||
self.EventSocketConns[idx] = NewDfltFsConnConfig()
|
||||
self.EventSocketConns[idx].loadFromJsonCfg(jsnConnCfg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -220,7 +267,7 @@ func NewDfltKamConnConfig() *KamConnConfig {
|
||||
|
||||
// Represents one connection instance towards Kamailio
|
||||
type KamConnConfig struct {
|
||||
EvapiAddr string
|
||||
Address string
|
||||
Reconnects int
|
||||
}
|
||||
|
||||
@@ -228,8 +275,8 @@ func (self *KamConnConfig) loadFromJsonCfg(jsnCfg *KamConnJsonCfg) error {
|
||||
if jsnCfg == nil {
|
||||
return nil
|
||||
}
|
||||
if jsnCfg.Evapi_addr != nil {
|
||||
self.EvapiAddr = *jsnCfg.Evapi_addr
|
||||
if jsnCfg.Address != nil {
|
||||
self.Address = *jsnCfg.Address
|
||||
}
|
||||
if jsnCfg.Reconnects != nil {
|
||||
self.Reconnects = *jsnCfg.Reconnects
|
||||
@@ -240,13 +287,13 @@ func (self *KamConnConfig) loadFromJsonCfg(jsnCfg *KamConnJsonCfg) error {
|
||||
// SM-Kamailio config section
|
||||
type SmKamConfig struct {
|
||||
Enabled bool
|
||||
HaRater []*HaPoolConfig
|
||||
HaCdrs []*HaPoolConfig
|
||||
RALsConns []*HaPoolConfig
|
||||
CDRsConns []*HaPoolConfig
|
||||
CreateCdr bool
|
||||
DebitInterval time.Duration
|
||||
MinCallDuration time.Duration
|
||||
MaxCallDuration time.Duration
|
||||
Connections []*KamConnConfig
|
||||
EvapiConns []*KamConnConfig
|
||||
}
|
||||
|
||||
func (self *SmKamConfig) loadFromJsonCfg(jsnCfg *SmKamJsonCfg) error {
|
||||
@@ -257,11 +304,19 @@ func (self *SmKamConfig) loadFromJsonCfg(jsnCfg *SmKamJsonCfg) error {
|
||||
if jsnCfg.Enabled != nil {
|
||||
self.Enabled = *jsnCfg.Enabled
|
||||
}
|
||||
if jsnCfg.Rater != nil {
|
||||
self.HaRater = []*HaPoolConfig{&HaPoolConfig{Server: *jsnCfg.Rater, Timeout: time.Duration(1) * time.Second}}
|
||||
if jsnCfg.Rals_conns != nil {
|
||||
self.RALsConns = make([]*HaPoolConfig, len(*jsnCfg.Rals_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Rals_conns {
|
||||
self.RALsConns[idx] = NewDfltHaPoolConfig()
|
||||
self.RALsConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Cdrs != nil {
|
||||
self.HaCdrs = []*HaPoolConfig{&HaPoolConfig{Server: *jsnCfg.Cdrs, Timeout: time.Duration(1) * time.Second}}
|
||||
if jsnCfg.Cdrs_conns != nil {
|
||||
self.CDRsConns = make([]*HaPoolConfig, len(*jsnCfg.Cdrs_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Cdrs_conns {
|
||||
self.CDRsConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CDRsConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Create_cdr != nil {
|
||||
self.CreateCdr = *jsnCfg.Create_cdr
|
||||
@@ -281,11 +336,11 @@ func (self *SmKamConfig) loadFromJsonCfg(jsnCfg *SmKamJsonCfg) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if jsnCfg.Connections != nil {
|
||||
self.Connections = make([]*KamConnConfig, len(*jsnCfg.Connections))
|
||||
for idx, jsnConnCfg := range *jsnCfg.Connections {
|
||||
self.Connections[idx] = NewDfltKamConnConfig()
|
||||
self.Connections[idx].loadFromJsonCfg(jsnConnCfg)
|
||||
if jsnCfg.Evapi_conns != nil {
|
||||
self.EvapiConns = make([]*KamConnConfig, len(*jsnCfg.Evapi_conns))
|
||||
for idx, jsnConnCfg := range *jsnCfg.Evapi_conns {
|
||||
self.EvapiConns[idx] = NewDfltKamConnConfig()
|
||||
self.EvapiConns[idx].loadFromJsonCfg(jsnConnCfg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -311,8 +366,8 @@ func (self *OsipsConnConfig) loadFromJsonCfg(jsnCfg *OsipsConnJsonCfg) error {
|
||||
type SmOsipsConfig struct {
|
||||
Enabled bool
|
||||
ListenUdp string
|
||||
HaRater []*HaPoolConfig
|
||||
HaCdrs []*HaPoolConfig
|
||||
RALsConns []*HaPoolConfig
|
||||
CDRsConns []*HaPoolConfig
|
||||
CreateCdr bool
|
||||
DebitInterval time.Duration
|
||||
MinCallDuration time.Duration
|
||||
@@ -329,11 +384,19 @@ func (self *SmOsipsConfig) loadFromJsonCfg(jsnCfg *SmOsipsJsonCfg) error {
|
||||
if jsnCfg.Listen_udp != nil {
|
||||
self.ListenUdp = *jsnCfg.Listen_udp
|
||||
}
|
||||
if jsnCfg.Rater != nil {
|
||||
self.HaRater = []*HaPoolConfig{&HaPoolConfig{Server: *jsnCfg.Rater, Timeout: time.Duration(1) * time.Second}}
|
||||
if jsnCfg.Rals_conns != nil {
|
||||
self.RALsConns = make([]*HaPoolConfig, len(*jsnCfg.Rals_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Rals_conns {
|
||||
self.RALsConns[idx] = NewDfltHaPoolConfig()
|
||||
self.RALsConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Cdrs != nil {
|
||||
self.HaCdrs = []*HaPoolConfig{&HaPoolConfig{Server: *jsnCfg.Cdrs, Timeout: time.Duration(1) * time.Second}}
|
||||
if jsnCfg.Cdrs_conns != nil {
|
||||
self.CDRsConns = make([]*HaPoolConfig, len(*jsnCfg.Cdrs_conns))
|
||||
for idx, jsnHaCfg := range *jsnCfg.Cdrs_conns {
|
||||
self.CDRsConns[idx] = NewDfltHaPoolConfig()
|
||||
self.CDRsConns[idx].loadFromJsonCfg(jsnHaCfg)
|
||||
}
|
||||
}
|
||||
if jsnCfg.Create_cdr != nil {
|
||||
self.CreateCdr = *jsnCfg.Create_cdr
|
||||
|
||||
@@ -29,14 +29,14 @@ func TesSmFsConfigLoadFromJsonCfg(t *testing.T) {
|
||||
Enabled: utils.BoolPointer(true),
|
||||
Create_cdr: utils.BoolPointer(true),
|
||||
Subscribe_park: utils.BoolPointer(true),
|
||||
Connections: &[]*FsConnJsonCfg{
|
||||
Event_socket_conns: &[]*FsConnJsonCfg{
|
||||
&FsConnJsonCfg{
|
||||
Server: utils.StringPointer("1.2.3.4:8021"),
|
||||
Address: utils.StringPointer("1.2.3.4:8021"),
|
||||
Password: utils.StringPointer("ClueCon"),
|
||||
Reconnects: utils.IntPointer(5),
|
||||
},
|
||||
&FsConnJsonCfg{
|
||||
Server: utils.StringPointer("2.3.4.5:8021"),
|
||||
Address: utils.StringPointer("2.3.4.5:8021"),
|
||||
Password: utils.StringPointer("ClueCon"),
|
||||
Reconnects: utils.IntPointer(5),
|
||||
},
|
||||
@@ -45,9 +45,9 @@ func TesSmFsConfigLoadFromJsonCfg(t *testing.T) {
|
||||
eSmFsConfig := &SmFsConfig{Enabled: true,
|
||||
CreateCdr: true,
|
||||
SubscribePark: true,
|
||||
Connections: []*FsConnConfig{
|
||||
&FsConnConfig{Server: "1.2.3.4:8021", Password: "ClueCon", Reconnects: 5},
|
||||
&FsConnConfig{Server: "1.2.3.4:8021", Password: "ClueCon", Reconnects: 5},
|
||||
EventSocketConns: []*FsConnConfig{
|
||||
&FsConnConfig{Address: "1.2.3.4:8021", Password: "ClueCon", Reconnects: 5},
|
||||
&FsConnConfig{Address: "1.2.3.4:8021", Password: "ClueCon", Reconnects: 5},
|
||||
},
|
||||
}
|
||||
smFsCfg := new(SmFsConfig)
|
||||
|
||||
@@ -21,8 +21,8 @@ package console
|
||||
import "github.com/cgrates/cgrates/apier/v1"
|
||||
|
||||
func init() {
|
||||
c := &CmdAddTriggers{
|
||||
name: "triggers_add",
|
||||
c := &CmdAccountAddTriggers{
|
||||
name: "account_triggers_add",
|
||||
rpcMethod: "ApierV1.AddAccountActionTriggers",
|
||||
rpcParams: &v1.AttrAddAccountActionTriggers{},
|
||||
}
|
||||
@@ -31,33 +31,33 @@ func init() {
|
||||
}
|
||||
|
||||
// Commander implementation
|
||||
type CmdAddTriggers struct {
|
||||
type CmdAccountAddTriggers struct {
|
||||
name string
|
||||
rpcMethod string
|
||||
rpcParams *v1.AttrAddAccountActionTriggers
|
||||
*CommandExecuter
|
||||
}
|
||||
|
||||
func (self *CmdAddTriggers) Name() string {
|
||||
func (self *CmdAccountAddTriggers) Name() string {
|
||||
return self.name
|
||||
}
|
||||
|
||||
func (self *CmdAddTriggers) RpcMethod() string {
|
||||
func (self *CmdAccountAddTriggers) RpcMethod() string {
|
||||
return self.rpcMethod
|
||||
}
|
||||
|
||||
func (self *CmdAddTriggers) RpcParams(reset bool) interface{} {
|
||||
func (self *CmdAccountAddTriggers) RpcParams(reset bool) interface{} {
|
||||
if reset || self.rpcParams == nil {
|
||||
self.rpcParams = &v1.AttrAddAccountActionTriggers{}
|
||||
}
|
||||
return self.rpcParams
|
||||
}
|
||||
|
||||
func (self *CmdAddTriggers) PostprocessRpcParams() error {
|
||||
func (self *CmdAccountAddTriggers) PostprocessRpcParams() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CmdAddTriggers) RpcResult() interface{} {
|
||||
func (self *CmdAccountAddTriggers) RpcResult() interface{} {
|
||||
var s string
|
||||
return &s
|
||||
}
|
||||
@@ -21,8 +21,8 @@ package console
|
||||
import "github.com/cgrates/cgrates/apier/v1"
|
||||
|
||||
func init() {
|
||||
c := &CmdRemoveTriggers{
|
||||
name: "triggers_remove",
|
||||
c := &CmdAccountRemoveTriggers{
|
||||
name: "account_triggers_remove",
|
||||
rpcMethod: "ApierV1.RemoveAccountActionTriggers",
|
||||
rpcParams: &v1.AttrRemoveAccountActionTriggers{},
|
||||
}
|
||||
@@ -31,33 +31,33 @@ func init() {
|
||||
}
|
||||
|
||||
// Commander implementation
|
||||
type CmdRemoveTriggers struct {
|
||||
type CmdAccountRemoveTriggers struct {
|
||||
name string
|
||||
rpcMethod string
|
||||
rpcParams *v1.AttrRemoveAccountActionTriggers
|
||||
*CommandExecuter
|
||||
}
|
||||
|
||||
func (self *CmdRemoveTriggers) Name() string {
|
||||
func (self *CmdAccountRemoveTriggers) Name() string {
|
||||
return self.name
|
||||
}
|
||||
|
||||
func (self *CmdRemoveTriggers) RpcMethod() string {
|
||||
func (self *CmdAccountRemoveTriggers) RpcMethod() string {
|
||||
return self.rpcMethod
|
||||
}
|
||||
|
||||
func (self *CmdRemoveTriggers) RpcParams(reset bool) interface{} {
|
||||
func (self *CmdAccountRemoveTriggers) RpcParams(reset bool) interface{} {
|
||||
if reset || self.rpcParams == nil {
|
||||
self.rpcParams = &v1.AttrRemoveAccountActionTriggers{}
|
||||
}
|
||||
return self.rpcParams
|
||||
}
|
||||
|
||||
func (self *CmdRemoveTriggers) PostprocessRpcParams() error {
|
||||
func (self *CmdAccountRemoveTriggers) PostprocessRpcParams() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CmdRemoveTriggers) RpcResult() interface{} {
|
||||
func (self *CmdAccountRemoveTriggers) RpcResult() interface{} {
|
||||
var s string
|
||||
return &s
|
||||
}
|
||||
@@ -21,8 +21,8 @@ package console
|
||||
import "github.com/cgrates/cgrates/apier/v1"
|
||||
|
||||
func init() {
|
||||
c := &CmdResetTriggers{
|
||||
name: "triggers_reset",
|
||||
c := &CmdAccountResetTriggers{
|
||||
name: "account_triggers_reset",
|
||||
rpcMethod: "ApierV1.ResetAccountActionTriggers",
|
||||
rpcParams: &v1.AttrRemoveAccountActionTriggers{},
|
||||
}
|
||||
@@ -31,33 +31,33 @@ func init() {
|
||||
}
|
||||
|
||||
// Commander implementation
|
||||
type CmdResetTriggers struct {
|
||||
type CmdAccountResetTriggers struct {
|
||||
name string
|
||||
rpcMethod string
|
||||
rpcParams *v1.AttrRemoveAccountActionTriggers
|
||||
*CommandExecuter
|
||||
}
|
||||
|
||||
func (self *CmdResetTriggers) Name() string {
|
||||
func (self *CmdAccountResetTriggers) Name() string {
|
||||
return self.name
|
||||
}
|
||||
|
||||
func (self *CmdResetTriggers) RpcMethod() string {
|
||||
func (self *CmdAccountResetTriggers) RpcMethod() string {
|
||||
return self.rpcMethod
|
||||
}
|
||||
|
||||
func (self *CmdResetTriggers) RpcParams(reset bool) interface{} {
|
||||
func (self *CmdAccountResetTriggers) RpcParams(reset bool) interface{} {
|
||||
if reset || self.rpcParams == nil {
|
||||
self.rpcParams = &v1.AttrRemoveAccountActionTriggers{}
|
||||
}
|
||||
return self.rpcParams
|
||||
}
|
||||
|
||||
func (self *CmdResetTriggers) PostprocessRpcParams() error {
|
||||
func (self *CmdAccountResetTriggers) PostprocessRpcParams() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CmdResetTriggers) RpcResult() interface{} {
|
||||
func (self *CmdAccountResetTriggers) RpcResult() interface{} {
|
||||
var s string
|
||||
return &s
|
||||
}
|
||||
63
console/account_trigger_set.go
Normal file
63
console/account_trigger_set.go
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2012-2015 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 console
|
||||
|
||||
import "github.com/cgrates/cgrates/apier/v1"
|
||||
|
||||
func init() {
|
||||
c := &CmdAccountSetTriggers{
|
||||
name: "account_triggers_set",
|
||||
rpcMethod: "ApierV1.SetAccountActionTriggers",
|
||||
rpcParams: &v1.AttrSetAccountActionTriggers{},
|
||||
}
|
||||
commands[c.Name()] = c
|
||||
c.CommandExecuter = &CommandExecuter{c}
|
||||
}
|
||||
|
||||
// Commander implementation
|
||||
type CmdAccountSetTriggers struct {
|
||||
name string
|
||||
rpcMethod string
|
||||
rpcParams *v1.AttrSetAccountActionTriggers
|
||||
*CommandExecuter
|
||||
}
|
||||
|
||||
func (self *CmdAccountSetTriggers) Name() string {
|
||||
return self.name
|
||||
}
|
||||
|
||||
func (self *CmdAccountSetTriggers) RpcMethod() string {
|
||||
return self.rpcMethod
|
||||
}
|
||||
|
||||
func (self *CmdAccountSetTriggers) RpcParams(reset bool) interface{} {
|
||||
if reset || self.rpcParams == nil {
|
||||
self.rpcParams = &v1.AttrSetAccountActionTriggers{}
|
||||
}
|
||||
return self.rpcParams
|
||||
}
|
||||
|
||||
func (self *CmdAccountSetTriggers) PostprocessRpcParams() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CmdAccountSetTriggers) RpcResult() interface{} {
|
||||
var s string
|
||||
return &s
|
||||
}
|
||||
@@ -18,7 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
package console
|
||||
|
||||
import "github.com/cgrates/cgrates/utils"
|
||||
import (
|
||||
"github.com/cgrates/cgrates/apier/v2"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
)
|
||||
|
||||
func init() {
|
||||
c := &CmdGetActions{
|
||||
@@ -33,7 +36,7 @@ func init() {
|
||||
type CmdGetActions struct {
|
||||
name string
|
||||
rpcMethod string
|
||||
rpcParams *StringWrapper
|
||||
rpcParams *v2.AttrGetActions
|
||||
*CommandExecuter
|
||||
}
|
||||
|
||||
@@ -47,7 +50,7 @@ func (self *CmdGetActions) RpcMethod() string {
|
||||
|
||||
func (self *CmdGetActions) RpcParams(reset bool) interface{} {
|
||||
if reset || self.rpcParams == nil {
|
||||
self.rpcParams = &StringWrapper{}
|
||||
self.rpcParams = &v2.AttrGetActions{}
|
||||
}
|
||||
return self.rpcParams
|
||||
}
|
||||
@@ -57,6 +60,6 @@ func (self *CmdGetActions) PostprocessRpcParams() error {
|
||||
}
|
||||
|
||||
func (self *CmdGetActions) RpcResult() interface{} {
|
||||
a := make([]*utils.TPAction, 0)
|
||||
a := make(map[string]engine.Actions, 0)
|
||||
return &a
|
||||
}
|
||||
|
||||
62
console/actions_remove.go
Normal file
62
console/actions_remove.go
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Real-time Charging System for Telecom & ISP environments
|
||||
Copyright (C) 2012-2015 ITsysCOM GmbH
|
||||
|
||||
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 console
|
||||
|
||||
import "github.com/cgrates/cgrates/apier/v1"
|
||||
|
||||
func init() {
|
||||
c := &CmdRemoveActions{
|
||||
name: "actions_remove",
|
||||
rpcMethod: "ApierV1.RemActions",
|
||||
}
|
||||
commands[c.Name()] = c
|
||||
c.CommandExecuter = &CommandExecuter{c}
|
||||
}
|
||||
|
||||
// Commander implementation
|
||||
type CmdRemoveActions struct {
|
||||
name string
|
||||
rpcMethod string
|
||||
rpcParams *v1.AttrRemActions
|
||||
*CommandExecuter
|
||||
}
|
||||
|
||||
func (self *CmdRemoveActions) Name() string {
|
||||
return self.name
|
||||
}
|
||||
|
||||
func (self *CmdRemoveActions) RpcMethod() string {
|
||||
return self.rpcMethod
|
||||
}
|
||||
|
||||
func (self *CmdRemoveActions) RpcParams(reset bool) interface{} {
|
||||
if reset || self.rpcParams == nil {
|
||||
self.rpcParams = &v1.AttrRemActions{}
|
||||
}
|
||||
return self.rpcParams
|
||||
}
|
||||
|
||||
func (self *CmdRemoveActions) PostprocessRpcParams() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CmdRemoveActions) RpcResult() interface{} {
|
||||
var s string
|
||||
return &s
|
||||
}
|
||||
@@ -27,7 +27,7 @@ func init() {
|
||||
c := &CmdSetAliases{
|
||||
name: "aliases_set",
|
||||
rpcMethod: "AliasesV1.SetAlias",
|
||||
rpcParams: &engine.Alias{Direction: utils.OUT},
|
||||
rpcParams: &engine.AttrAddAlias{Alias: &engine.Alias{Direction: utils.OUT}},
|
||||
}
|
||||
commands[c.Name()] = c
|
||||
c.CommandExecuter = &CommandExecuter{c}
|
||||
@@ -37,7 +37,7 @@ func init() {
|
||||
type CmdSetAliases struct {
|
||||
name string
|
||||
rpcMethod string
|
||||
rpcParams *engine.Alias
|
||||
rpcParams *engine.AttrAddAlias
|
||||
*CommandExecuter
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (self *CmdSetAliases) RpcMethod() string {
|
||||
|
||||
func (self *CmdSetAliases) RpcParams(reset bool) interface{} {
|
||||
if reset || self.rpcParams == nil {
|
||||
self.rpcParams = &engine.Alias{Direction: utils.OUT}
|
||||
self.rpcParams = &engine.AttrAddAlias{Alias: &engine.Alias{Direction: utils.OUT}}
|
||||
}
|
||||
return self.rpcParams
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ import "github.com/cgrates/cgrates/apier/v1"
|
||||
func init() {
|
||||
c := &CmdSetTriggers{
|
||||
name: "triggers_set",
|
||||
rpcMethod: "ApierV1.SetAccountActionTriggers",
|
||||
rpcParams: &v1.AttrSetAccountActionTriggers{},
|
||||
rpcMethod: "ApierV1.SetActionTrigger",
|
||||
rpcParams: &v1.AttrSetActionTrigger{},
|
||||
}
|
||||
commands[c.Name()] = c
|
||||
c.CommandExecuter = &CommandExecuter{c}
|
||||
@@ -34,7 +34,7 @@ func init() {
|
||||
type CmdSetTriggers struct {
|
||||
name string
|
||||
rpcMethod string
|
||||
rpcParams *v1.AttrSetAccountActionTriggers
|
||||
rpcParams *v1.AttrSetActionTrigger
|
||||
*CommandExecuter
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func (self *CmdSetTriggers) RpcMethod() string {
|
||||
|
||||
func (self *CmdSetTriggers) RpcParams(reset bool) interface{} {
|
||||
if reset || self.rpcParams == nil {
|
||||
self.rpcParams = &v1.AttrSetAccountActionTriggers{}
|
||||
self.rpcParams = &v1.AttrSetActionTrigger{}
|
||||
}
|
||||
return self.rpcParams
|
||||
}
|
||||
|
||||
@@ -19,48 +19,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package console
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/apier/v1"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
c := &CmdUpdateAliases{
|
||||
name: "aliases_update",
|
||||
rpcMethod: "AliasesV1.UpdateAlias",
|
||||
rpcParams: &engine.Alias{Direction: utils.OUT},
|
||||
c := &CmdGetTriggers{
|
||||
name: "triggers",
|
||||
rpcMethod: "ApierV1.GetActionTriggers",
|
||||
rpcParams: &v1.AttrGetActionTriggers{},
|
||||
}
|
||||
commands[c.Name()] = c
|
||||
c.CommandExecuter = &CommandExecuter{c}
|
||||
}
|
||||
|
||||
// Commander implementation
|
||||
type CmdUpdateAliases struct {
|
||||
type CmdGetTriggers struct {
|
||||
name string
|
||||
rpcMethod string
|
||||
rpcParams *engine.Alias
|
||||
rpcParams *v1.AttrGetActionTriggers
|
||||
*CommandExecuter
|
||||
}
|
||||
|
||||
func (self *CmdUpdateAliases) Name() string {
|
||||
func (self *CmdGetTriggers) Name() string {
|
||||
return self.name
|
||||
}
|
||||
|
||||
func (self *CmdUpdateAliases) RpcMethod() string {
|
||||
func (self *CmdGetTriggers) RpcMethod() string {
|
||||
return self.rpcMethod
|
||||
}
|
||||
|
||||
func (self *CmdUpdateAliases) RpcParams(reset bool) interface{} {
|
||||
func (self *CmdGetTriggers) RpcParams(reset bool) interface{} {
|
||||
if reset || self.rpcParams == nil {
|
||||
self.rpcParams = &engine.Alias{Direction: utils.OUT}
|
||||
self.rpcParams = &v1.AttrGetActionTriggers{}
|
||||
}
|
||||
return self.rpcParams
|
||||
}
|
||||
|
||||
func (self *CmdUpdateAliases) PostprocessRpcParams() error {
|
||||
func (self *CmdGetTriggers) PostprocessRpcParams() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CmdUpdateAliases) RpcResult() interface{} {
|
||||
var s string
|
||||
return &s
|
||||
func (self *CmdGetTriggers) RpcResult() interface{} {
|
||||
atr := engine.ActionTriggers{}
|
||||
return &atr
|
||||
}
|
||||
@@ -6,333 +6,373 @@
|
||||
// This file contains the default configuration hardcoded into CGRateS.
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
//"general": {
|
||||
// "http_skip_tls_verify": false, // if enabled Http Client will accept any TLS certificate
|
||||
// "rounding_decimals": 5, // system level precision for floats
|
||||
// "dbdata_encoding": "msgpack", // encoding used to store object data in strings: <msgpack|json>
|
||||
// "tpexport_dir": "/var/log/cgrates/tpe", // path towards export folder for offline Tariff Plans
|
||||
// "http_failed_dir": "/var/log/cgrates/http_failed", // directory path where we store failed http requests
|
||||
// "default_reqtype": "*rated", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
// "default_category": "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
|
||||
// "default_timezone": "Local", // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
// "connect_attempts": 3, // initial server connect attempts
|
||||
// "reconnects": -1, // number of retries in case of connection lost
|
||||
// "response_cache_ttl": "3s", // the life span of a cached response
|
||||
// "internal_ttl": "2m", // maximum duration to wait for internal connections before giving up
|
||||
//},
|
||||
// "general": {
|
||||
// "http_skip_tls_verify": false, // if enabled Http Client will accept any TLS certificate
|
||||
// "rounding_decimals": 5, // system level precision for floats
|
||||
// "dbdata_encoding": "msgpack", // encoding used to store object data in strings: <msgpack|json>
|
||||
// "tpexport_dir": "/var/log/cgrates/tpe", // path towards export folder for offline Tariff Plans
|
||||
// "http_failed_dir": "/var/log/cgrates/http_failed", // directory path where we store failed http requests
|
||||
// "default_request_type": "*rated", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
// "default_category": "call", // default category to consider when missing from requests
|
||||
// "default_tenant": "cgrates.org", // default tenant to consider when missing from requests
|
||||
// "default_timezone": "Local", // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
// "connect_attempts": 3, // initial server connect attempts
|
||||
// "reconnects": -1, // number of retries in case of connection lost
|
||||
// "response_cache_ttl": "0s", // the life span of a cached response
|
||||
// "internal_ttl": "2m", // maximum duration to wait for internal connections before giving up
|
||||
// },
|
||||
|
||||
|
||||
//"listen": {
|
||||
// "rpc_json": "127.0.0.1:2012", // RPC JSON listening address
|
||||
// "rpc_gob": "127.0.0.1:2013", // RPC GOB listening address
|
||||
// "http": "127.0.0.1:2080", // HTTP listening address
|
||||
//},
|
||||
// "listen": {
|
||||
// "rpc_json": "127.0.0.1:2012", // RPC JSON listening address
|
||||
// "rpc_gob": "127.0.0.1:2013", // RPC GOB listening address
|
||||
// "http": "127.0.0.1:2080", // HTTP listening address
|
||||
// },
|
||||
|
||||
|
||||
//"tariffplan_db": { // database used to store active tariff plan configuration
|
||||
// "db_type": "redis", // tariffplan_db type: <redis>
|
||||
// "db_host": "127.0.0.1", // tariffplan_db host address
|
||||
// "db_port": 6379, // port to reach the tariffplan_db
|
||||
// "db_name": "10", // tariffplan_db name to connect to
|
||||
// "db_user": "", // sername to use when connecting to tariffplan_db
|
||||
// "db_passwd": "", // password to use when connecting to tariffplan_db
|
||||
//},
|
||||
// "tariffplan_db": { // database used to store active tariff plan configuration
|
||||
// "db_type": "redis", // tariffplan_db type: <redis|mongo>
|
||||
// "db_host": "127.0.0.1", // tariffplan_db host address
|
||||
// "db_port": 6379, // port to reach the tariffplan_db
|
||||
// "db_name": "10", // tariffplan_db name to connect to
|
||||
// "db_user": "", // sername to use when connecting to tariffplan_db
|
||||
// "db_password": "", // password to use when connecting to tariffplan_db
|
||||
// },
|
||||
|
||||
|
||||
//"data_db": { // database used to store runtime data (eg: accounts, cdr stats)
|
||||
// "db_type": "redis", // data_db type: <redis>
|
||||
// "db_host": "127.0.0.1", // data_db host address
|
||||
// "db_port": 6379, // data_db port to reach the database
|
||||
// "db_name": "11", // data_db database name to connect to
|
||||
// "db_user": "", // username to use when connecting to data_db
|
||||
// "db_passwd": "", // password to use when connecting to data_db
|
||||
// "load_history_size": 10, // Number of records in the load history
|
||||
//},
|
||||
// "data_db": { // database used to store runtime data (eg: accounts, cdr stats)
|
||||
// "db_type": "redis", // data_db type: <redis|mongo>
|
||||
// "db_host": "127.0.0.1", // data_db host address
|
||||
// "db_port": 6379, // data_db port to reach the database
|
||||
// "db_name": "11", // data_db database name to connect to
|
||||
// "db_user": "", // username to use when connecting to data_db
|
||||
// "db_password": "", // password to use when connecting to data_db
|
||||
// "load_history_size": 10, // Number of records in the load history
|
||||
// },
|
||||
|
||||
|
||||
//"stor_db": { // database used to store offline tariff plans and CDRs
|
||||
// "db_type": "mysql", // stor database type to use: <mysql|postgres>
|
||||
// "db_host": "127.0.0.1", // the host to connect to
|
||||
// "db_port": 3306, // the port to reach the stordb
|
||||
// "db_name": "cgrates", // stor database name
|
||||
// "db_user": "cgrates", // username to use when connecting to stordb
|
||||
// "db_passwd": "CGRateS.org", // password to use when connecting to stordb
|
||||
// "max_open_conns": 100, // maximum database connections opened
|
||||
// "max_idle_conns": 10, // maximum database connections idle
|
||||
//},
|
||||
// "stor_db": { // database used to store offline tariff plans and CDRs
|
||||
// "db_type": "mysql", // stor database type to use: <mongo|mysql|postgres>
|
||||
// "db_host": "127.0.0.1", // the host to connect to
|
||||
// "db_port": 3306, // the port to reach the stordb
|
||||
// "db_name": "cgrates", // stor database name
|
||||
// "db_user": "cgrates", // username to use when connecting to stordb
|
||||
// "db_password": "CGRateS.org", // password to use when connecting to stordb
|
||||
// "max_open_conns": 100, // maximum database connections opened
|
||||
// "max_idle_conns": 10, // maximum database connections idle
|
||||
// "cdrs_indexes": [], // indexes on cdrs table to speed up queries, used only in case of mongo
|
||||
// },
|
||||
|
||||
|
||||
//"balancer": {
|
||||
// "enabled": false, // start Balancer service: <true|false>
|
||||
//},
|
||||
// "balancer": {
|
||||
// "enabled": false, // start Balancer service: <true|false>
|
||||
// },
|
||||
|
||||
|
||||
//"rater": {
|
||||
// "enabled": false, // enable Rater service: <true|false>
|
||||
// "balancer": "", // register to balancer as worker: <""|internal|x.y.z.y:1234>
|
||||
// "cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality: <""|internal|x.y.z.y:1234>
|
||||
// "historys": "", // address where to reach the history service, empty to disable history functionality: <""|internal|x.y.z.y:1234>
|
||||
// "pubsubs": "", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
|
||||
// "users": "", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
|
||||
// "aliases": "", // address where to reach the aliases service, empty to disable aliases functionality: <""|internal|x.y.z.y:1234>
|
||||
// "rp_subject_prefix_matching": false, // enables prefix matching for the rating profile subject
|
||||
//},
|
||||
// "rals": {
|
||||
// "enabled": false, // enable Rater service: <true|false>
|
||||
// "balancer": "", // register to balancer as worker: <""|*internal|x.y.z.y:1234>
|
||||
// "cdrstats_conns": [], // address where to reach the cdrstats service, empty to disable stats functionality: <""|*internal|x.y.z.y:1234>
|
||||
// "historys_conns": [], // address where to reach the history service, empty to disable history functionality: <""|*internal|x.y.z.y:1234>
|
||||
// "pubsubs_conns": [], // address where to reach the pubusb service, empty to disable pubsub functionality: <""|*internal|x.y.z.y:1234>
|
||||
// "users_conns": [], // address where to reach the user service, empty to disable user profile functionality: <""|*internal|x.y.z.y:1234>
|
||||
// "aliases_conns": [], // address where to reach the aliases service, empty to disable aliases functionality: <""|*internal|x.y.z.y:1234>
|
||||
// "rp_subject_prefix_matching": false, // enables prefix matching for the rating profile subject
|
||||
// "lcr_subject_prefix_matching": false // enables prefix matching for the lcr subject
|
||||
// },
|
||||
|
||||
|
||||
//"scheduler": {
|
||||
// "enabled": false, // start Scheduler service: <true|false>
|
||||
//},
|
||||
// "scheduler": {
|
||||
// "enabled": false, // start Scheduler service: <true|false>
|
||||
// },
|
||||
|
||||
|
||||
//"cdrs": {
|
||||
// "enabled": false, // start the CDR Server service: <true|false>
|
||||
// "extra_fields": [], // extra fields to store in CDRs for non-generic CDRs
|
||||
// "store_cdrs": true, // store cdrs in storDb
|
||||
// "rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
// "pubsubs": "", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
|
||||
// "users": "", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
|
||||
// "aliases": "", // address where to reach the aliases service, empty to disable aliases functionality: <""|internal|x.y.z.y:1234>
|
||||
// "cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
// "cdr_replication":[], // replicate the raw CDR to a number of servers
|
||||
//},
|
||||
// "cdrs": {
|
||||
// "enabled": false, // start the CDR Server service: <true|false>
|
||||
// "extra_fields": [], // extra fields to store in CDRs for non-generic CDRs
|
||||
// "store_cdrs": true, // store cdrs in storDb
|
||||
// "rals_conns": [
|
||||
// {"address": "*internal"} // address where to reach the Rater for cost calculation, empty to disable functionality: <""|*internal|x.y.z.y:1234>
|
||||
// ],
|
||||
// "pubsubs_conns": [], // address where to reach the pubusb service, empty to disable pubsub functionality: <""|*internal|x.y.z.y:1234>
|
||||
// "users_conns": [], // address where to reach the user service, empty to disable user profile functionality: <""|*internal|x.y.z.y:1234>
|
||||
// "aliases_conns": [], // address where to reach the aliases service, empty to disable aliases functionality: <""|*internal|x.y.z.y:1234>
|
||||
// "cdrstats_conns": [], // address where to reach the cdrstats service, empty to disable stats functionality<""|*internal|x.y.z.y:1234>
|
||||
// "cdr_replication":[] // replicate the raw CDR to a number of servers
|
||||
// },
|
||||
|
||||
|
||||
//"cdrstats": {
|
||||
// "enabled": false, // starts the cdrstats service: <true|false>
|
||||
// "save_interval": "1m", // interval to save changed stats into dataDb storage
|
||||
//},
|
||||
// "cdrstats": {
|
||||
// "enabled": false, // starts the cdrstats service: <true|false>
|
||||
// "save_interval": "1m", // interval to save changed stats into dataDb storage
|
||||
// },
|
||||
|
||||
|
||||
//"cdre": {
|
||||
// "*default": {
|
||||
// "cdr_format": "csv", // exported CDRs format <csv>
|
||||
// "field_separator": ",",
|
||||
// "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes)
|
||||
// "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems)
|
||||
// "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems)
|
||||
// "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
|
||||
// "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding
|
||||
// "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents)
|
||||
// "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export
|
||||
// "mask_length": 0, // length of the destination suffix to be masked
|
||||
// "export_dir": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed
|
||||
// "header_fields": [], // template of the exported header fields
|
||||
// "content_fields": [ // template of the exported content fields
|
||||
// {"tag": "CgrId", "field_id": "CgrId", "type": "*composed", "value": "CgrId"},
|
||||
// {"tag":"RunId", "field_id": "MediationRunId", "type": "*composed", "value": "MediationRunId"},
|
||||
// {"tag":"Tor", "field_id": "TOR", "type": "*composed", "value": "TOR"},
|
||||
// {"tag":"AccId", "field_id": "AccId", "type": "*composed", "value": "AccId"},
|
||||
// {"tag":"ReqType", "field_id": "ReqType", "type": "*composed", "value": "ReqType"},
|
||||
// {"tag":"Direction", "field_id": "Direction", "type": "*composed", "value": "Direction"},
|
||||
// {"tag":"Tenant", "field_id": "Tenant", "type": "*composed", "value": "Tenant"},
|
||||
// {"tag":"Category", "field_id": "Category", "type": "*composed", "value": "Category"},
|
||||
// {"tag":"Account", "field_id": "Account", "type": "*composed", "value": "Account"},
|
||||
// {"tag":"Subject", "field_id": "Subject", "type": "*composed", "value": "Subject"},
|
||||
// {"tag":"Destination", "field_id": "Destination", "type": "*composed", "value": "Destination"},
|
||||
// {"tag":"SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
// {"tag":"AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
// {"tag":"Usage", "field_id": "Usage", "type": "*composed", "value": "Usage"},
|
||||
// {"tag":"Cost", "field_id": "Cost", "type": "*composed", "value": "Cost"},
|
||||
// ],
|
||||
// "trailer_fields": [], // template of the exported trailer fields
|
||||
// }
|
||||
//},
|
||||
// "cdre": {
|
||||
// "*default": {
|
||||
// "cdr_format": "csv", // exported CDRs format <csv>
|
||||
// "field_separator": ",",
|
||||
// "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes)
|
||||
// "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems)
|
||||
// "mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems)
|
||||
// "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems)
|
||||
// "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
|
||||
// "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding
|
||||
// "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents)
|
||||
// "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export
|
||||
// "mask_length": 0, // length of the destination suffix to be masked
|
||||
// "export_folder": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed
|
||||
// "header_fields": [], // template of the exported header fields
|
||||
// "content_fields": [ // template of the exported content fields
|
||||
// {"tag": "CGRID", "field_id": "CGRID", "type": "*composed", "value": "CGRID"},
|
||||
// {"tag":"RunID", "field_id": "RunID", "type": "*composed", "value": "RunID"},
|
||||
// {"tag":"TOR", "field_id": "ToR", "type": "*composed", "value": "ToR"},
|
||||
// {"tag":"OriginID", "field_id": "OriginID", "type": "*composed", "value": "OriginID"},
|
||||
// {"tag":"RequestType", "field_id": "RequestType", "type": "*composed", "value": "RequestType"},
|
||||
// {"tag":"Direction", "field_id": "Direction", "type": "*composed", "value": "Direction"},
|
||||
// {"tag":"Tenant", "field_id": "Tenant", "type": "*composed", "value": "Tenant"},
|
||||
// {"tag":"Category", "field_id": "Category", "type": "*composed", "value": "Category"},
|
||||
// {"tag":"Account", "field_id": "Account", "type": "*composed", "value": "Account"},
|
||||
// {"tag":"Subject", "field_id": "Subject", "type": "*composed", "value": "Subject"},
|
||||
// {"tag":"Destination", "field_id": "Destination", "type": "*composed", "value": "Destination"},
|
||||
// {"tag":"SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
// {"tag":"AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
// {"tag":"Usage", "field_id": "Usage", "type": "*composed", "value": "Usage"},
|
||||
// {"tag":"Cost", "field_id": "Cost", "type": "*composed", "value": "Cost"},
|
||||
// ],
|
||||
// "trailer_fields": [], // template of the exported trailer fields
|
||||
// }
|
||||
// },
|
||||
|
||||
|
||||
//"cdrc": {
|
||||
// "*default": {
|
||||
// "enabled": false, // enable CDR client functionality
|
||||
// "dry_run": false, // do not send the CDRs to CDRS, just parse them
|
||||
// "cdrs": "internal", // address where to reach CDR server. <internal|x.y.z.y:1234>
|
||||
// "cdr_format": "csv", // CDR file format <csv|freeswitch_csv|fwv|opensips_flatstore>
|
||||
// "field_separator": ",", // separator used in case of csv files
|
||||
// "timezone": "", // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
// "run_delay": 0, // sleep interval in seconds between consecutive runs, 0 to use automation via inotify
|
||||
// "max_open_files": 1024, // maximum simultaneous files to process, 0 for unlimited
|
||||
// "data_usage_multiply_factor": 1024, // conversion factor for data usage
|
||||
// "cdr_in_dir": "/var/log/cgrates/cdrc/in", // absolute path towards the directory where the CDRs are stored
|
||||
// "cdr_out_dir": "/var/log/cgrates/cdrc/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
// "failed_calls_prefix": "missed_calls", // used in case of flatstore CDRs to avoid searching for BYE records
|
||||
// "cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
// "cdr_filter": "", // filter CDR records to import
|
||||
// "continue_on_success": false, // continue to the next template if executed
|
||||
// "partial_record_cache": "10s", // duration to cache partial records when not pairing
|
||||
// "header_fields": [], // template of the import header fields
|
||||
// "content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
// {"tag": "tor", "field_id": "TOR", "type": "*composed", "value": "2", "mandatory": true},
|
||||
// {"tag": "accid", "field_id": "AccId", "type": "*composed", "value": "3", "mandatory": true},
|
||||
// {"tag": "reqtype", "field_id": "ReqType", "type": "*composed", "value": "4", "mandatory": true},
|
||||
// {"tag": "direction", "field_id": "Direction", "type": "*composed", "value": "5", "mandatory": true},
|
||||
// {"tag": "tenant", "field_id": "Tenant", "type": "*composed", "value": "6", "mandatory": true},
|
||||
// {"tag": "category", "field_id": "Category", "type": "*composed", "value": "7", "mandatory": true},
|
||||
// {"tag": "account", "field_id": "Account", "type": "*composed", "value": "8", "mandatory": true},
|
||||
// {"tag": "subject", "field_id": "Subject", "type": "*composed", "value": "9", "mandatory": true},
|
||||
// {"tag": "destination", "field_id": "Destination", "type": "*composed", "value": "10", "mandatory": true},
|
||||
// {"tag": "setup_time", "field_id": "SetupTime", "type": "*composed", "value": "11", "mandatory": true},
|
||||
// {"tag": "answer_time", "field_id": "AnswerTime", "type": "*composed", "value": "12", "mandatory": true},
|
||||
// {"tag": "usage", "field_id": "Usage", "type": "*composed", "value": "13", "mandatory": true},
|
||||
// ],
|
||||
// "trailer_fields": [], // template of the import trailer fields
|
||||
// }
|
||||
//},
|
||||
|
||||
//"sm_generic": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests
|
||||
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
// "cdrs": "internal", // address where to reach CDR Server <""|internal|x.y.z.y:1234>
|
||||
// "debit_interval": "0s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
//},
|
||||
// "cdrc": [
|
||||
// {
|
||||
// "id": "*default", // identifier of the CDRC runner
|
||||
// "enabled": false, // enable CDR client functionality
|
||||
// "dry_run": false, // do not send the CDRs to CDRS, just parse them
|
||||
// "cdrs_conns": [
|
||||
// {"address": "*internal"} // address where to reach CDR server. <*internal|x.y.z.y:1234>
|
||||
// ],
|
||||
// "cdr_format": "csv", // CDR file format <csv|freeswitch_csv|fwv|opensips_flatstore>
|
||||
// "field_separator": ",", // separator used in case of csv files
|
||||
// "timezone": "", // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
// "run_delay": 0, // sleep interval in seconds between consecutive runs, 0 to use automation via inotify
|
||||
// "max_open_files": 1024, // maximum simultaneous files to process, 0 for unlimited
|
||||
// "data_usage_multiply_factor": 1024, // conversion factor for data usage
|
||||
// "cdr_in_dir": "/var/log/cgrates/cdrc/in", // absolute path towards the directory where the CDRs are stored
|
||||
// "cdr_out_dir": "/var/log/cgrates/cdrc/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
// "failed_calls_prefix": "missed_calls", // used in case of flatstore CDRs to avoid searching for BYE records
|
||||
// "cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
// "cdr_filter": "", // filter CDR records to import
|
||||
// "continue_on_success": false, // continue to the next template if executed
|
||||
// "partial_record_cache": "10s", // duration to cache partial records when not pairing
|
||||
// "header_fields": [], // template of the import header fields
|
||||
// "content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
// {"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "2", "mandatory": true},
|
||||
// {"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "3", "mandatory": true},
|
||||
// {"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "4", "mandatory": true},
|
||||
// {"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "5", "mandatory": true},
|
||||
// {"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "6", "mandatory": true},
|
||||
// {"tag": "Category", "field_id": "Category", "type": "*composed", "value": "7", "mandatory": true},
|
||||
// {"tag": "Account", "field_id": "Account", "type": "*composed", "value": "8", "mandatory": true},
|
||||
// {"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "9", "mandatory": true},
|
||||
// {"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "10", "mandatory": true},
|
||||
// {"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "11", "mandatory": true},
|
||||
// {"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "12", "mandatory": true},
|
||||
// {"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "13", "mandatory": true},
|
||||
// ],
|
||||
// "trailer_fields": [], // template of the import trailer fields
|
||||
// },
|
||||
// ],
|
||||
|
||||
|
||||
//"sm_freeswitch": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
// "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
|
||||
// "create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
// "extra_fields": [], // extra fields to store in auth/CDRs when creating them
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "min_dur_low_balance": "5s", // threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval)
|
||||
// "low_balance_ann_file": "", // file to be played when low balance is reached for prepaid calls
|
||||
// "empty_balance_context": "", // if defined, prepaid calls will be transfered to this context on empty balance
|
||||
// "empty_balance_ann_file": "", // file to be played before disconnecting prepaid calls on empty balance (applies only if no context defined)
|
||||
// "subscribe_park": true, // subscribe via fsock to receive park events
|
||||
// "channel_sync_interval": "5m", // sync channels with freeswitch regularly
|
||||
// "connections":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
// {"server": "127.0.0.1:8021", "password": "ClueCon", "reconnects": 5}
|
||||
// ],
|
||||
//},
|
||||
// "sm_generic": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests
|
||||
// "rals_conns": [
|
||||
// {"address": "*internal"} // address where to reach the Rater <""|*internal|127.0.0.1:2013>
|
||||
// ],
|
||||
// "cdrs_conns": [
|
||||
// {"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <*internal|x.y.z.y:1234>
|
||||
// ],
|
||||
// "debit_interval": "0s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "session_ttl": "0s", // time after a session with no updates is terminated, not defined by default
|
||||
//"session_ttl_last_used": "", // tweak LastUsed for sessions timing-out, not defined by default
|
||||
//"session_ttl_usage": "", // tweak Usage for sessions timing-out, not defined by default
|
||||
// },
|
||||
|
||||
|
||||
//"sm_kamailio": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
// "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
|
||||
// "create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "connections":[ // instantiate connections to multiple Kamailio servers
|
||||
// {"evapi_addr": "127.0.0.1:8448", "reconnects": 5}
|
||||
// ],
|
||||
//},
|
||||
// "sm_freeswitch": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "rals_conns": [
|
||||
// {"address": "*internal"} // address where to reach the Rater <""|*internal|127.0.0.1:2013>
|
||||
// ],
|
||||
// "cdrs_conns": [
|
||||
// {"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <*internal|x.y.z.y:1234>
|
||||
// ],
|
||||
// "create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
// "extra_fields": [], // extra fields to store in auth/CDRs when creating them
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "min_dur_low_balance": "5s", // threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval)
|
||||
// "low_balance_ann_file": "", // file to be played when low balance is reached for prepaid calls
|
||||
// "empty_balance_context": "", // if defined, prepaid calls will be transfered to this context on empty balance
|
||||
// "empty_balance_ann_file": "", // file to be played before disconnecting prepaid calls on empty balance (applies only if no context defined)
|
||||
// "subscribe_park": true, // subscribe via fsock to receive park events
|
||||
// "channel_sync_interval": "5m", // sync channels with freeswitch regularly
|
||||
// "max_wait_connection": "2s", // maximum duration to wait for a connection to be retrieved from the pool
|
||||
// "event_socket_conns":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
// {"address": "127.0.0.1:8021", "password": "ClueCon", "reconnects": 5}
|
||||
// ],
|
||||
// },
|
||||
|
||||
|
||||
//"sm_opensips": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "listen_udp": "127.0.0.1:2020", // address where to listen for datagram events coming from OpenSIPS
|
||||
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
// "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
|
||||
// "reconnects": 5, // number of reconnects if connection is lost
|
||||
// "create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "events_subscribe_interval": "60s", // automatic events subscription to OpenSIPS, 0 to disable it
|
||||
// "mi_addr": "127.0.0.1:8020", // address where to reach OpenSIPS MI to send session disconnects
|
||||
//},
|
||||
// "sm_kamailio": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "rals_conns": [
|
||||
// {"address": "*internal"} // address where to reach the Rater <""|*internal|127.0.0.1:2013>
|
||||
// ],
|
||||
// "cdrs_conns": [
|
||||
// {"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <*internal|x.y.z.y:1234>
|
||||
// ],
|
||||
// "create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "evapi_conns":[ // instantiate connections to multiple Kamailio servers
|
||||
// {"address": "127.0.0.1:8448", "reconnects": 5}
|
||||
// ],
|
||||
// },
|
||||
|
||||
|
||||
//"diameter_agent": {
|
||||
// "enabled": false, // enables the diameter agent: <true|false>
|
||||
// "listen": "127.0.0.1:3868", // address where to listen for diameter requests <x.y.z.y:1234>
|
||||
// "dictionaries_dir": "/usr/share/cgrates/diameter/dict/", // path towards directory holding additional dictionaries to load
|
||||
// "sm_generic": "internal", // connection towards SMG component for session management
|
||||
// "timezone": "", // timezone for timestamps where not specified, empty for general defaults <""|UTC|Local|$IANA_TZ_DB>
|
||||
// "origin_host": "CGR-DA", // diameter Origin-Host AVP used in replies
|
||||
// "origin_realm": "cgrates.org", // diameter Origin-Realm AVP used in replies
|
||||
// "vendor_id": 0, // diameter Vendor-Id AVP used in replies
|
||||
// "product_name": "CGRateS", // diameter Product-Name AVP used in replies
|
||||
// "request_processors": [
|
||||
// {
|
||||
// "id": "*default", // formal identifier of this processor
|
||||
// "dry_run": false, // do not send the CDRs to CDRS, just parse them
|
||||
// "request_filter": "Subscription-Id>Subscription-Id-Type(0)", // filter requests processed by this processor
|
||||
// "continue_on_success": false, // continue to the next template if executed
|
||||
// "content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
// {"tag": "tor", "field_id": "TOR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
// {"tag": "accid", "field_id": "AccId", "type": "*composed", "value": "Session-Id", "mandatory": true},
|
||||
// {"tag": "reqtype", "field_id": "ReqType", "type": "*composed", "value": "^*users", "mandatory": true},
|
||||
// {"tag": "direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
// {"tag": "tenant", "field_id": "Tenant", "type": "*composed", "value": "^*users", "mandatory": true},
|
||||
// {"tag": "category", "field_id": "Category", "type": "*composed", "value": "^call_;~Service-Information>IN-Information>Calling-Vlr-Number:s/^$/33000/;~Service-Information>IN-Information>Calling-Vlr-Number:s/^(\\d{5})/${1}/", "mandatory": true},
|
||||
// {"tag": "account", "field_id": "Account", "type": "*composed", "value": "^*users", "mandatory": true},
|
||||
// {"tag": "subject", "field_id": "Subject", "type": "*composed", "value": "^*users", "mandatory": true},
|
||||
// {"tag": "destination", "field_id": "Destination", "type": "*composed", "value": "Service-Information>IN-Information>Real-Called-Number", "mandatory": true},
|
||||
// {"tag": "setup_time", "field_id": "SetupTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
// {"tag": "answer_time", "field_id": "AnswerTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
// {"tag": "usage", "field_id": "Usage", "type": "*composed", "value": "Requested-Service-Unit>CC-Time", "mandatory": true},
|
||||
// {"tag": "subscriber_id", "field_id": "SubscriberId", "type": "*composed", "value": "Subscription-Id>Subscription-Id-Data", "mandatory": true},
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
//},
|
||||
// "sm_opensips": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "listen_udp": "127.0.0.1:2020", // address where to listen for datagram events coming from OpenSIPS
|
||||
// "rals_conns": [
|
||||
// {"address": "*internal"} // address where to reach the Rater <""|*internal|127.0.0.1:2013>
|
||||
// ],
|
||||
// "cdrs_conns": [
|
||||
// {"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <*internal|x.y.z.y:1234>
|
||||
// ],
|
||||
// "reconnects": 5, // number of reconnects if connection is lost
|
||||
// "create_cdr": false, // create CDR out of events and sends it to CDRS component
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "events_subscribe_interval": "60s", // automatic events subscription to OpenSIPS, 0 to disable it
|
||||
// "mi_addr": "127.0.0.1:8020", // address where to reach OpenSIPS MI to send session disconnects
|
||||
// },
|
||||
|
||||
|
||||
//"historys": {
|
||||
// "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
|
||||
//},
|
||||
// "diameter_agent": {
|
||||
// "enabled": false, // enables the diameter agent: <true|false>
|
||||
// "listen": "127.0.0.1:3868", // address where to listen for diameter requests <x.y.z.y:1234>
|
||||
// "dictionaries_dir": "/usr/share/cgrates/diameter/dict/", // path towards directory holding additional dictionaries to load
|
||||
// "sm_generic_conns": [
|
||||
// {"address": "*internal"} // connection towards SMG component for session management
|
||||
// ],
|
||||
// "pubsubs_conns": [], // address where to reach the pubusb service, empty to disable pubsub functionality: <""|*internal|x.y.z.y:1234>
|
||||
// "create_cdr": true, // create CDR out of CCR terminate and send it to SMG component
|
||||
// "debit_interval": "5m", // interval for CCR updates
|
||||
// "timezone": "", // timezone for timestamps where not specified, empty for general defaults <""|UTC|Local|$IANA_TZ_DB>
|
||||
// "dialect": "huawei", // the diameter dialect used in the communication, supported: <huawei>
|
||||
// "origin_host": "CGR-DA", // diameter Origin-Host AVP used in replies
|
||||
// "origin_realm": "cgrates.org", // diameter Origin-Realm AVP used in replies
|
||||
// "vendor_id": 0, // diameter Vendor-Id AVP used in replies
|
||||
// "product_name": "CGRateS", // diameter Product-Name AVP used in replies
|
||||
// "request_processors": [
|
||||
// {
|
||||
// "id": "*default", // formal identifier of this processor
|
||||
// "dry_run": false, // do not send the events to SMG, just log them
|
||||
// "publish_event": false, // if enabled, it will publish internal event to pubsub
|
||||
// "request_filter": "Subscription-Id>Subscription-Id-Type(0)", // filter requests processed by this processor
|
||||
// "flags": [], // flags to influence processing behavior
|
||||
// "continue_on_success": false, // continue to the next template if executed
|
||||
// "append_cca": true, // when continuing will append cca fields to the previous ones
|
||||
// "ccr_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
// {"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
// {"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "Session-Id", "mandatory": true},
|
||||
// {"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*users", "mandatory": true},
|
||||
// {"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
// {"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^*users", "mandatory": true},
|
||||
// {"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
// {"tag": "Account", "field_id": "Account", "type": "*composed", "value": "^*users", "mandatory": true},
|
||||
// {"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "^*users", "mandatory": true},
|
||||
// {"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "Service-Information>IN-Information>Real-Called-Number", "mandatory": true},
|
||||
// {"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
// {"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
// {"tag": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*ccr_usage", "mandatory": true},
|
||||
// {"tag": "SubscriberID", "field_id": "SubscriberId", "type": "*composed", "value": "Subscription-Id>Subscription-Id-Data", "mandatory": true},
|
||||
// ],
|
||||
// "cca_fields":[ // fields returned in CCA
|
||||
// {"tag": "GrantedUnits", "field_id": "Granted-Service-Unit>CC-Time", "type": "*handler", "handler_id": "*cca_usage", "mandatory": true},
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
|
||||
|
||||
//"pubsubs": {
|
||||
// "enabled": false, // starts PubSub service: <true|false>.
|
||||
//},
|
||||
// "historys": {
|
||||
// "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
|
||||
// },
|
||||
|
||||
|
||||
//"aliases": {
|
||||
// "enabled": false, // starts Aliases service: <true|false>.
|
||||
//},
|
||||
// "pubsubs": {
|
||||
// "enabled": false, // starts PubSub service: <true|false>.
|
||||
// },
|
||||
|
||||
|
||||
//"users": {
|
||||
// "enabled": false, // starts User service: <true|false>.
|
||||
// "indexes": [], // user profile field indexes
|
||||
//},
|
||||
// "aliases": {
|
||||
// "enabled": false, // starts Aliases service: <true|false>.
|
||||
// },
|
||||
|
||||
|
||||
//"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
|
||||
//},
|
||||
// "users": {
|
||||
// "enabled": false, // starts User service: <true|false>.
|
||||
// "indexes": [], // user profile field indexes
|
||||
// },
|
||||
|
||||
|
||||
//"suretax": {
|
||||
// "url": "", // API url
|
||||
// "client_number": "", // client number, provided by SureTax
|
||||
// "validation_key": "", // validation key provided by SureTax
|
||||
// "business_unit": "", // client’s Business Unit
|
||||
// "timezone": "Local", // convert the time of the events to this timezone before sending request out <UTC|Local|$IANA_TZ_DB>
|
||||
// "include_local_cost": false, // sum local calculated cost with tax one in final cost
|
||||
// "return_file_code": "0", // default or Quote purposes <0|Q>
|
||||
// "response_group": "03", // determines how taxes are grouped for the response <03|13>
|
||||
// "response_type": "D4", // determines the granularity of taxes and (optionally) the decimal precision for the tax calculations and amounts in the response
|
||||
// "regulatory_code": "03", // provider type
|
||||
// "client_tracking": "CgrId", // template extracting client information out of StoredCdr; <$RSRFields>
|
||||
// "customer_number": "Subject", // template extracting customer number out of StoredCdr; <$RSRFields>
|
||||
// "orig_number": "Subject", // template extracting origination number out of StoredCdr; <$RSRFields>
|
||||
// "term_number": "Destination", // template extracting termination number out of StoredCdr; <$RSRFields>
|
||||
// "bill_to_number": "", // template extracting billed to number out of StoredCdr; <$RSRFields>
|
||||
// "zipcode": "", // template extracting billing zip code out of StoredCdr; <$RSRFields>
|
||||
// "plus4": "", // template extracting billing zip code extension out of StoredCdr; <$RSRFields>
|
||||
// "p2pzipcode": "", // template extracting secondary zip code out of StoredCdr; <$RSRFields>
|
||||
// "p2pplus4": "", // template extracting secondary zip code extension out of StoredCdr; <$RSRFields>
|
||||
// "units": "^1", // template extracting number of “lines” or unique charges contained within the revenue out of StoredCdr; <$RSRFields>
|
||||
// "unit_type": "^00", // template extracting number of unique access lines out of StoredCdr; <$RSRFields>
|
||||
// "tax_included": "^0", // template extracting tax included in revenue out of StoredCdr; <$RSRFields>
|
||||
// "tax_situs_rule": "^04", // template extracting tax situs rule out of StoredCdr; <$RSRFields>
|
||||
// "trans_type_code": "^010101", // template extracting transaction type indicator out of StoredCdr; <$RSRFields>
|
||||
// "sales_type_code": "^R", // template extracting sales type code out of StoredCdr; <$RSRFields>
|
||||
// "tax_exemption_code_list": "", // template extracting tax exemption code list out of StoredCdr; <$RSRFields>
|
||||
//},
|
||||
// "mailer": {
|
||||
// "server": "localhost", // the server to use when sending emails out
|
||||
// "auth_user": "cgrates", // authenticate to email server using this user
|
||||
// "auth_password": "CGRateS.org", // authenticate to email server with this password
|
||||
// "from_address": "cgr-mailer@localhost.localdomain" // from address used when sending emails out
|
||||
// },
|
||||
|
||||
}
|
||||
|
||||
// "suretax": {
|
||||
// "url": "", // API url
|
||||
// "client_number": "", // client number, provided by SureTax
|
||||
// "validation_key": "", // validation key provided by SureTax
|
||||
// "business_unit": "", // client’s Business Unit
|
||||
// "timezone": "Local", // convert the time of the events to this timezone before sending request out <UTC|Local|$IANA_TZ_DB>
|
||||
// "include_local_cost": false, // sum local calculated cost with tax one in final cost
|
||||
// "return_file_code": "0", // default or Quote purposes <0|Q>
|
||||
// "response_group": "03", // determines how taxes are grouped for the response <03|13>
|
||||
// "response_type": "D4", // determines the granularity of taxes and (optionally) the decimal precision for the tax calculations and amounts in the response
|
||||
// "regulatory_code": "03", // provider type
|
||||
// "client_tracking": "CGRID", // template extracting client information out of StoredCdr; <$RSRFields>
|
||||
// "customer_number": "Subject", // template extracting customer number out of StoredCdr; <$RSRFields>
|
||||
// "orig_number": "Subject", // template extracting origination number out of StoredCdr; <$RSRFields>
|
||||
// "term_number": "Destination", // template extracting termination number out of StoredCdr; <$RSRFields>
|
||||
// "bill_to_number": "", // template extracting billed to number out of StoredCdr; <$RSRFields>
|
||||
// "zipcode": "", // template extracting billing zip code out of StoredCdr; <$RSRFields>
|
||||
// "plus4": "", // template extracting billing zip code extension out of StoredCdr; <$RSRFields>
|
||||
// "p2pzipcode": "", // template extracting secondary zip code out of StoredCdr; <$RSRFields>
|
||||
// "p2pplus4": "", // template extracting secondary zip code extension out of StoredCdr; <$RSRFields>
|
||||
// "units": "^1", // template extracting number of “lines” or unique charges contained within the revenue out of StoredCdr; <$RSRFields>
|
||||
// "unit_type": "^00", // template extracting number of unique access lines out of StoredCdr; <$RSRFields>
|
||||
// "tax_included": "^0", // template extracting tax included in revenue out of StoredCdr; <$RSRFields>
|
||||
// "tax_situs_rule": "^04", // template extracting tax situs rule out of StoredCdr; <$RSRFields>
|
||||
// "trans_type_code": "^010101", // template extracting transaction type indicator out of StoredCdr; <$RSRFields>
|
||||
// "sales_type_code": "^R", // template extracting sales type code out of StoredCdr; <$RSRFields>
|
||||
// "tax_exemption_code_list": "", // template extracting tax exemption code list out of StoredCdr; <$RSRFields>
|
||||
// },
|
||||
|
||||
}
|
||||
@@ -10,11 +10,17 @@
|
||||
"http": ":2080", // HTTP listening address
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
"pubsubs": "internal",
|
||||
"users": "internal",
|
||||
"aliases": "internal",
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"users_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"aliases_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
"http": ":2080", // HTTP listening address
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
"aliases": "internal"
|
||||
"aliases_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
@@ -21,7 +23,9 @@
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
"rals_conns": [
|
||||
{"address": "*internal"} // address where to reach the Rater <""|*internal|127.0.0.1:2013>
|
||||
],
|
||||
},
|
||||
|
||||
"aliases": {
|
||||
@@ -34,4 +38,9 @@
|
||||
}
|
||||
},
|
||||
|
||||
"cdrstats": {
|
||||
"enabled": true, // starts the cdrstats service: <true|false>
|
||||
"save_interval": "0s", // interval to save changed stats into dataDb storage
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
57
data/conf/samples/cdrccsv/cgrates.json
Normal file
57
data/conf/samples/cdrccsv/cgrates.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
|
||||
// Real-time Charging System for Telecom & ISP environments
|
||||
// Copyright (C) ITsysCOM GmbH
|
||||
//
|
||||
// This file contains the default configuration hardcoded into CGRateS.
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
|
||||
"rals": {
|
||||
"enabled": true // so we can query CDRs
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true,
|
||||
"rals_conns": [], // no rating support, just *raw CDR testing
|
||||
},
|
||||
|
||||
|
||||
|
||||
"cdrc": [
|
||||
{
|
||||
"id": "*default",
|
||||
"enabled": true,
|
||||
"cdr_in_dir": "/tmp/cdrctests/csvit1/in",
|
||||
"cdr_out_dir": "/tmp/cdrctests/csvit1/out",
|
||||
"cdr_source_id": "csvit1",
|
||||
},
|
||||
{
|
||||
"id": "*CSVit2", // identifier of the CDRC runner
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"field_separator": ";",
|
||||
"cdr_in_dir": "/tmp/cdrctests/csvit2/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cdrctests/csvit2/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
"cdr_source_id": "csvit2", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "0", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "1", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "2", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^call", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed", "value": "3", "mandatory": true},
|
||||
{"tag": "Subject", "field_id": "Subject", "type": "*composed", "value": "3", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "~4:s/0([1-9]\\d+)/+49${1}/", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "5", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "5", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra3", "field_id": "HDRExtra3", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra2", "field_id": "HDRExtra2", "type": "*composed", "value": "6", "mandatory": true},
|
||||
{"tag": "HDRExtra1", "field_id": "HDRExtra1", "type": "*composed", "value": "6", "mandatory": true},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
@@ -22,10 +22,13 @@
|
||||
},
|
||||
|
||||
|
||||
"cdrc": {
|
||||
"FLATSTORE": {
|
||||
"cdrc": [
|
||||
{
|
||||
"id": "FLATSTORE",
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"cdrs": "internal", // address where to reach CDR server. <internal|x.y.z.y:1234>
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"} // address where to reach CDR server. <*internal|x.y.z.y:1234>
|
||||
],
|
||||
"cdr_format": "opensips_flatstore", // CDR file format <csv|freeswitch_csv|fwv|opensips_flatstore>
|
||||
"field_separator": "|", // separator used in case of csv files
|
||||
"run_delay": 0, // sleep interval in seconds between consecutive runs, 0 to use automation via inotify
|
||||
@@ -54,6 +57,6 @@
|
||||
{"tag": "DialogId", "cdr_field_id": "DialogId", "type": "cdrfield", "value": "11"},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
@@ -22,11 +22,14 @@
|
||||
},
|
||||
|
||||
|
||||
"cdrc": {
|
||||
"FWV1": {
|
||||
"cdrc": [
|
||||
{
|
||||
"id": "FWV1",
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"dry_run": true,
|
||||
"cdrs": "internal", // address where to reach CDR server. <internal|x.y.z.y:1234>
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"} // address where to reach CDR server. <*internal|x.y.z.y:1234>
|
||||
],
|
||||
"cdr_format": "fwv", // CDR file format <csv|freeswitch_csv|fwv|opensips_flatstore>
|
||||
"cdr_in_dir": "/tmp/cgr_fwv/cdrc/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgr_fwv/cdrc/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
@@ -60,6 +63,6 @@
|
||||
{"tag": "TotalDuration", "type": "metatag", "metatag_id":"total_duration", "value": "150", "width": 12},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Used in apier_local_tests
|
||||
// Starts rater, cdrs and mediator connecting over internal channel
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"store_cdrs": false, // store cdrs in storDb
|
||||
"cdr_replication":[ // replicate the rated CDR to a number of servers
|
||||
{"transport": "*http_post", "server": "http://127.0.0.1:12080/cdr_http", "attempts": 1},
|
||||
//{"transport": "*http_post", "server": "http://127.0.0.1:8000/mycdr"},
|
||||
{"transport": "*http_post", "address": "http://127.0.0.1:12080/cdr_http", "attempts": 1},
|
||||
//{"transport": "*http_post", "address": "http://127.0.0.1:8000/mycdr"},
|
||||
|
||||
],
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"http": "127.0.0.1:12080", // HTTP listening address
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
|
||||
@@ -5,24 +5,31 @@
|
||||
// Starts rater, cdrs and mediator connecting over internal channel
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2012", // RPC JSON listening address
|
||||
"rpc_gob": ":2013", // RPC GOB listening address
|
||||
"http": ":2080", // HTTP listening address
|
||||
"rpc_json": ":2012",
|
||||
"rpc_gob": ":2013",
|
||||
"http": ":2080",
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
"cdrstats": "internal",
|
||||
"rals": {
|
||||
"enabled": true,
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"store_cdrs": false, // store cdrs in storDb
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
"cdrstats": "internal", // address where to reach the cdrstats service. Empty to disable stats gathering out of mediated CDRs <""|internal|x.y.z.y:1234>
|
||||
"enabled": true,
|
||||
"store_cdrs": false,
|
||||
"rals_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
]
|
||||
},
|
||||
|
||||
"cdrstats": {
|
||||
"enabled": true, // starts the cdrstats service: <true|false>
|
||||
"enabled": true,
|
||||
"save_interval": "1s",
|
||||
},
|
||||
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
},
|
||||
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
"rals_conns": [
|
||||
{"address": "*internal"} // address where to reach the Rater for cost calculation, empty to disable functionality: <""|*internal|x.y.z.y:1234>
|
||||
],
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
// Used in apier_local_tests
|
||||
// Starts rater, cdrs and mediator connecting over internal channel
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
"rals_conns": [
|
||||
{"address": "*internal"} // address where to reach the Rater for cost calculation, empty to disable functionality: <""|*internal|x.y.z.y:1234>
|
||||
],
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
},
|
||||
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
"rals_conns": [
|
||||
{"address": "*internal"} // address where to reach the Rater for cost calculation, empty to disable functionality: <""|*internal|x.y.z.y:1234>
|
||||
],
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,32 +10,38 @@
|
||||
"http": ":2080", // HTTP listening address
|
||||
},
|
||||
|
||||
//"tariffplan_db": { // database used to store offline tariff plans and CDRs
|
||||
// "db_type": "mongo", // stor database type to use: <mysql|postgres>
|
||||
// "db_host": "127.0.0.1", // the host to connect to
|
||||
// "db_port": 27017, // the port to reach the stordb
|
||||
// "db_name": "tpdb",
|
||||
//},
|
||||
//
|
||||
//"data_db": { // database used to store offline tariff plans and CDRs
|
||||
// "db_type": "mongo", // stor database type to use: <mysql|postgres>
|
||||
// "db_host": "127.0.0.1", // the host to connect to
|
||||
// "db_port": 27017, // the port to reach the stordb
|
||||
// "db_name": "datadb",
|
||||
//},
|
||||
"tariffplan_db": { // database used to store offline tariff plans and CDRs
|
||||
"db_type": "mongo", // stor database type to use: <mysql|postgres>
|
||||
"db_host": "127.0.0.1", // the host to connect to
|
||||
"db_port": 27017, // the port to reach the stordb
|
||||
"db_name": "tpdb",
|
||||
},
|
||||
|
||||
"data_db": { // database used to store offline tariff plans and CDRs
|
||||
"db_type": "mongo", // stor database type to use: <mysql|postgres>
|
||||
"db_host": "127.0.0.1", // the host to connect to
|
||||
"db_port": 27017, // the port to reach the stordb
|
||||
"db_name": "datadb",
|
||||
},
|
||||
|
||||
"stor_db": { // database used to store offline tariff plans and CDRs
|
||||
"db_type": "mongo", // stor database type to use: <mysql|postgres>
|
||||
"db_host": "127.0.0.1", // the host to connect to
|
||||
"db_port": 27017, // the port to reach the stordb
|
||||
"db_name": "stordb",
|
||||
"db_name": "stordb",
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
"pubsubs": "internal",
|
||||
"users": "internal",
|
||||
"aliases": "internal",
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"users_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"aliases_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
|
||||
@@ -10,26 +10,35 @@
|
||||
"http": ":2080", // HTTP listening address
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
"pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
|
||||
"users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
|
||||
"aliases": "internal",
|
||||
"rals": {
|
||||
"enabled": true,
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"users_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"aliases_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
"enabled": true, // start Scheduler service: <true|false>
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
"enabled": true,
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"cdrstats": {
|
||||
"enabled": true, // starts the cdrstats service: <true|false>
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"pubsubs": {
|
||||
@@ -47,13 +56,13 @@
|
||||
|
||||
"sm_generic": {
|
||||
"enabled": true,
|
||||
"rater": "internal",
|
||||
"cdrs": "internal",
|
||||
},
|
||||
|
||||
"diameter_agent": {
|
||||
"enabled": true,
|
||||
"pubsubs": "internal",
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
110
data/conf/samples/dmtagent/data.json
Normal file
110
data/conf/samples/dmtagent/data.json
Normal file
@@ -0,0 +1,110 @@
|
||||
|
||||
{
|
||||
|
||||
"diameter_agent": {
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "data_init", // formal identifier of this processor
|
||||
"dry_run": false, // do not send the events to SMG, just log them
|
||||
"request_filter": "Service-Context-Id(^gprs);CC-Request-Type(1)", // filter requests processed by this processor
|
||||
"continue_on_success": false, // continue to the next template if executed
|
||||
"ccr_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*data", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "Session-Id", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*prepaid", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^generic", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*grouped", "value": "Subscription-Id>Subscription-Id-Data", "field_filter":"Subscription-Id>Subscription-Id-Type(0)", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*constant", "value": "data"},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*constant", "value": "2048"},
|
||||
],
|
||||
"cca_fields": [
|
||||
{"tag": "ResultCode", "field_id": "Result-Code", "type": "*constant", "value": "^2001"},
|
||||
{"tag": "ResultCode", "field_filter": "CGRMaxUsage(0)", "field_id": "Result-Code", "type": "*constant", "value": "4010"},
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "data_update_grp1", // formal identifier of this processor
|
||||
"dry_run": false, // do not send the events to SMG, just log them
|
||||
"request_filter": "Service-Context-Id(^gprs);CC-Request-Type(2);Multiple-Services-Credit-Control>Rating-Group(1)", // filter requests processed by this processor
|
||||
"continue_on_success": true, // continue to the next template if executed
|
||||
"ccr_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*data", "mandatory": true},
|
||||
{"tag": "InitialOriginID", "field_id": "InitialOriginID", "type": "*composed", "value": "Session-Id", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "Session-Id", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "^_grp1", "append": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*prepaid", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^generic", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*grouped", "value": "Subscription-Id>Subscription-Id-Data", "field_filter":"Subscription-Id>Subscription-Id-Type(0)", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*constant", "value": "data"},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*constant", "value": "2048"},
|
||||
{"tag": "LastUsed", "field_id": "LastUsed", "field_filter":"Multiple-Services-Credit-Control>Rating-Group(1)", "type": "*handler", "handler_id": "*sum",
|
||||
"value": "Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets;^|;Multiple-Services-Credit-Control>Used-Service-Unit>CC-Output-Octets"},
|
||||
],
|
||||
"cca_fields": [
|
||||
{"tag": "ResultCode", "field_id": "Result-Code", "type": "*constant", "value": "^2001"},
|
||||
{"tag": "ResultCode", "field_filter": "CGRMaxUsage(0)", "field_id": "Result-Code", "type": "*constant", "value": "4010"},
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "data_update_grp2", // formal identifier of this processor
|
||||
"dry_run": false, // do not send the events to SMG, just log them
|
||||
"request_filter": "Service-Context-Id(^gprs);CC-Request-Type(2);Multiple-Services-Credit-Control>Rating-Group(2)", // filter requests processed by this processor
|
||||
"continue_on_success": true, // continue to the next template if executed
|
||||
"ccr_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*data", "mandatory": true},
|
||||
{"tag": "InitialOriginID", "field_id": "InitialOriginID", "type": "*composed", "value": "Session-Id", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "Session-Id", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "^_grp2", "append": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*prepaid", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^generic", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*grouped", "value": "Subscription-Id>Subscription-Id-Data", "field_filter":"Subscription-Id>Subscription-Id-Type(0)", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*constant", "value": "data"},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*constant", "value": "2048"},
|
||||
{"tag": "LastUsed", "field_id": "LastUsed", "field_filter":"Multiple-Services-Credit-Control>Rating-Group(2)", "type": "*handler", "handler_id": "*sum",
|
||||
"value": "Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets;^|;Multiple-Services-Credit-Control>Used-Service-Unit>CC-Output-Octets"},
|
||||
],
|
||||
"cca_fields": [
|
||||
{"tag": "ResultCode", "field_id": "Result-Code", "type": "*constant", "value": "^2001"},
|
||||
{"tag": "ResultCode", "field_filter": "CGRMaxUsage(0)", "field_id": "Result-Code", "type": "*constant", "value": "4010"},
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "data_terminate", // formal identifier of this processor
|
||||
"dry_run": false, // do not send the events to SMG, just log them
|
||||
"request_filter": "Service-Context-Id(^gprs);CC-Request-Type(3)", // filter requests processed by this processor
|
||||
"continue_on_success": false, // continue to the next template if executed
|
||||
"ccr_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*data", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "Session-Id", "mandatory": true},
|
||||
{"tag": "OriginIDPrefix", "field_id": "OriginIDPrefix", "type": "*composed", "value": "Session-Id", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*prepaid", "mandatory": true},
|
||||
{"tag": "Direction", "field_id": "Direction", "type": "*composed", "value": "^*out", "mandatory": true},
|
||||
{"tag": "Tenant", "field_id": "Tenant", "type": "*composed", "value": "^cgrates.org", "mandatory": true},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*composed", "value": "^generic", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*grouped", "value": "Subscription-Id>Subscription-Id-Data", "field_filter":"Subscription-Id>Subscription-Id-Type(0)", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*constant", "value": "data"},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed", "value": "Event-Timestamp", "mandatory": true},
|
||||
{"tag": "LastUsed", "field_id": "LastUsed", "type": "*handler", "handler_id": "*sum",
|
||||
"value": "Multiple-Services-Credit-Control>Used-Service-Unit>CC-Input-Octets;^|;Multiple-Services-Credit-Control>Used-Service-Unit>CC-Output-Octets"},
|
||||
],
|
||||
"cca_fields": [
|
||||
{"tag": "ResultCode", "field_id": "Result-Code", "type": "*constant", "value": "^2001"}
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,9 +6,11 @@
|
||||
"http": ":2080", // HTTP listening address
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
@@ -17,13 +19,14 @@
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"cdrstats": {
|
||||
"enabled": true, // starts the cdrstats service: <true|false>
|
||||
"save_interval": "5s"
|
||||
"save_interval": "5s"
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
{
|
||||
// Contains CDRC template for FreeSWITCH CDR
|
||||
|
||||
"cdrc": {
|
||||
"CDRC-CSV2": {
|
||||
"cdrc": [
|
||||
{
|
||||
"id": "CDRC-CSV2",
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"cdr_in_dir": "/tmp/cgrates/cdrc_fs/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgrates/cdrc_fs/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
@@ -22,6 +23,6 @@
|
||||
{"tag": "usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "~8:s/^(\\d+)$/${1}s/", "mandatory": true},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
}
|
||||
|
||||
45
data/conf/samples/hapool/cgrrater1/cgr.json
Normal file
45
data/conf/samples/hapool/cgrrater1/cgr.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"listen": {
|
||||
"rpc_json": ":2014",
|
||||
"rpc_gob": ":2015",
|
||||
"http": ":2081",
|
||||
},
|
||||
|
||||
"rals": {
|
||||
"enabled": true,
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"users_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"aliases_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"cdrstats": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"pubsubs": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"aliases": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"users": {
|
||||
"enabled": true,
|
||||
"indexes": ["SubscriberId"],
|
||||
},
|
||||
|
||||
}
|
||||
46
data/conf/samples/hapool/cgrrater2/cgr.json
Normal file
46
data/conf/samples/hapool/cgrrater2/cgr.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2016",
|
||||
"rpc_gob": ":2017",
|
||||
"http": ":2082",
|
||||
},
|
||||
|
||||
"rals": {
|
||||
"enabled": true,
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"users_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"aliases_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"cdrstats": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"pubsubs": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"aliases": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"users": {
|
||||
"enabled": true,
|
||||
"indexes": ["SubscriberId"],
|
||||
},
|
||||
|
||||
}
|
||||
27
data/conf/samples/hapool/cgrsmg1/cgr.json
Normal file
27
data/conf/samples/hapool/cgrsmg1/cgr.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"listen": {
|
||||
"rpc_json": "127.0.0.1:2018", // RPC JSON listening address
|
||||
"rpc_gob": "127.0.0.1:2019", // RPC GOB listening address
|
||||
"http": "127.0.0.1:2083", // HTTP listening address
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rals_conns": [
|
||||
{"address": "127.0.0.1:2014"},
|
||||
{"address": "127.0.0.1:2016"}
|
||||
],
|
||||
"cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
},
|
||||
|
||||
"sm_generic": {
|
||||
"enabled": true,
|
||||
"rals_conns": [
|
||||
{"address": "127.0.0.1:2014"},
|
||||
{"address": "127.0.0.1:2016"}
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <internal|x.y.z.y:1234>
|
||||
],
|
||||
},
|
||||
}
|
||||
28
data/conf/samples/hapool/cgrsmg2/cgr.json
Normal file
28
data/conf/samples/hapool/cgrsmg2/cgr.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"listen": {
|
||||
"rpc_json": "127.0.0.1:2020", // RPC JSON listening address
|
||||
"rpc_gob": "127.0.0.1:2021", // RPC GOB listening address
|
||||
"http": "127.0.0.1:2084", // HTTP listening address
|
||||
},
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rals_conns": [
|
||||
{"address": "127.0.0.1:2014"},
|
||||
{"address": "127.0.0.1:2016"}
|
||||
],
|
||||
"cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
},
|
||||
|
||||
"sm_generic": {
|
||||
"enabled": true,
|
||||
"rals_conns": [
|
||||
{"address": "127.0.0.1:2014"},
|
||||
{"address": "127.0.0.1:2016"}
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"} // address where to reach CDR Server, empty to disable CDR capturing <internal|x.y.z.y:1234>
|
||||
],
|
||||
},
|
||||
|
||||
}
|
||||
10
data/conf/samples/hapool/dagent/cgr.json
Normal file
10
data/conf/samples/hapool/dagent/cgr.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"diameter_agent": {
|
||||
"enabled": true,
|
||||
"listen": "127.0.0.1:3868",
|
||||
"sm_generic_conns": [
|
||||
{"address": "127.0.0.1:2018"},
|
||||
{"address": "127.0.0.1:2020"}
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
// Should be the second file loaded
|
||||
|
||||
"general": {
|
||||
"default_reqtype": "*pseudoprepaid", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
"default_request_type": "*pseudoprepaid", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
},
|
||||
|
||||
"cdre": {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Used in mediator_local_test
|
||||
// Starts rater, cdrs and mediator connecting over internal channel
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
@@ -14,17 +14,18 @@
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"mediator": "internal", // address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
},
|
||||
|
||||
"cdrc": {
|
||||
"CDRC-CSV1": {
|
||||
"cdrc": [
|
||||
{
|
||||
"id": "CDRC-CSV1",
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"cdr_in_dir": "/tmp/cgrates/cdrc1/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgrates/cdrc1/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
"cdr_source_id": "csv1", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
},
|
||||
"CDRC-CSV2": {
|
||||
{
|
||||
"id": "CDRC-CSV2",
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"cdr_in_dir": "/tmp/cgrates/cdrc2/in", // absolute path towards the directory where the CDRs are stored
|
||||
"cdr_out_dir": "/tmp/cgrates/cdrc2/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
@@ -44,7 +45,8 @@
|
||||
{"cdr_field_id": "usage", "value": "~9:s/^(\\d+)$/${1}s/"},
|
||||
],
|
||||
},
|
||||
"CDRC-CSV3": {
|
||||
{
|
||||
"id": "CDRC-CSV3",
|
||||
"enabled": true, // enable CDR client functionality
|
||||
"field_separator": ";", // separator used in case of csv files
|
||||
"cdr_in_dir": "/tmp/cgrates/cdrc3/in", // absolute path towards the directory where the CDRs are stored
|
||||
@@ -65,11 +67,7 @@
|
||||
{"cdr_field_id": "usage", "value": "~6:s/^(\\d+)$/${1}s/"},
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
"mediator": {
|
||||
"enabled": true, // starts Mediator service: <true|false>.
|
||||
},
|
||||
],
|
||||
|
||||
"cdre": {
|
||||
"CDRE-FW1": {
|
||||
|
||||
17
data/conf/samples/multiral1/cgrates.json
Normal file
17
data/conf/samples/multiral1/cgrates.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
// CGRateS Configuration file
|
||||
//
|
||||
// Used for multiple RAL configuration tests
|
||||
// Starts rater, scheduler
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2012", // RPC JSON listening address
|
||||
"rpc_gob": ":2013", // RPC GOB listening address
|
||||
"http": ":2080", // HTTP listening address
|
||||
},
|
||||
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
}
|
||||
17
data/conf/samples/multiral2/cgrates.json
Normal file
17
data/conf/samples/multiral2/cgrates.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
// CGRateS Configuration file
|
||||
//
|
||||
// Used for multiple RAL configuration tests
|
||||
// Starts RAL
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":12012", // RPC JSON listening address
|
||||
"rpc_gob": ":12013", // RPC GOB listening address
|
||||
"http": ":12080", // HTTP listening address
|
||||
},
|
||||
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
# Real-time Charging System for Telecom & ISP environments
|
||||
# Copyright (C) ITsysCOM GmbH
|
||||
#
|
||||
# This file contains the default configuration hardcoded into CGRateS.
|
||||
# This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
[global]
|
||||
rpc_json_listen = :2012 # RPC JSON listening address
|
||||
|
||||
[rater]
|
||||
enabled = true # Enable RaterCDRSExportPath service: <true|false>.
|
||||
|
||||
[scheduler]
|
||||
enabled = true # Starts Scheduler service: <true|false>.
|
||||
|
||||
[cdrs]
|
||||
enabled = true # Start the CDR Server service: <true|false>.
|
||||
mediator = internal # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
|
||||
# cdrstats = # Address where to reach the cdrstats service: <internal|x.y.z.y:1234>
|
||||
|
||||
[mediator]
|
||||
enabled = true # Starts Mediator service: <true|false>.
|
||||
# rater = internal # Address where to reach the Rater: <internal|x.y.z.y:1234>
|
||||
# cdrstats = internal # Address where to reach the cdrstats service: <internal|x.y.z.y:1234>
|
||||
|
||||
[cdrstats]
|
||||
enabled = true # Starts the cdrstats service: <true|false>
|
||||
#queue_length = 50 # Number of items in the stats buffer
|
||||
time_window = 1h # Will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow
|
||||
save_interval = 5s
|
||||
# metrics = ASR, ACD, ACC # Stat metric ids to build
|
||||
# setup_interval = # Filter on CDR SetupTime
|
||||
# tors = # Filter on CDR TOR fields
|
||||
# cdr_hosts= # Filter on CDR CdrHost fields
|
||||
# cdr_sources = # Filter on CDR CdrSource fields
|
||||
# req_types = # Filter on CDR ReqType fields
|
||||
# directions = # Filter on CDR Direction fields
|
||||
# tenants = # Filter on CDR Tenant fields
|
||||
# categories = # Filter on CDR Category fields
|
||||
# accounts = # Filter on CDR Account fields
|
||||
# subjects = # Filter on CDR Subject fields
|
||||
# destination_prefixes = # Filter on CDR Destination prefixes
|
||||
# usage_interval = # Filter on CDR Usage
|
||||
# mediation_run_ids = # Filter on CDR MediationRunId fields
|
||||
# rated_accounts = # Filter on CDR RatedAccount fields
|
||||
# rated_subjects = # Filter on CDR RatedSubject fields
|
||||
# cost_intervals = # Filter on CDR Cost
|
||||
|
||||
[session_manager]
|
||||
enabled = true # Starts SessionManager service: <true|false>
|
||||
switch_type = opensips # Defines the type of switch behind: <freeswitch>
|
||||
|
||||
[opensips]
|
||||
listen_udp = :2020 # Address where to listen for datagram events coming from OpenSIPS
|
||||
mi_addr = 172.16.254.77:8020 # Adress where to reach OpenSIPS mi_datagram module
|
||||
|
||||
[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
|
||||
25
data/conf/samples/smfs/smfs.json
Normal file
25
data/conf/samples/smfs/smfs.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
|
||||
// Real-time Charging System for Telecom & ISP environments
|
||||
// Copyright (C) ITsysCOM GmbH
|
||||
//
|
||||
// This file contains the default configuration hardcoded into CGRateS.
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
|
||||
"sm_freeswitch": {
|
||||
"enabled": true,
|
||||
"rals_conns": [
|
||||
{"address": "127.0.0.1:2013"}
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "127.0.0.1:2013"}
|
||||
],
|
||||
"debit_interval": "5s",
|
||||
"channel_sync_interval": "10s",
|
||||
"event_socket_conns":[
|
||||
{"address": "127.0.0.1:8021", "password": "ClueCon", "reconnects": 5}
|
||||
],
|
||||
},
|
||||
|
||||
}
|
||||
@@ -4,13 +4,17 @@
|
||||
// Used for cgradmin
|
||||
// Starts rater, scheduler
|
||||
|
||||
"general": {
|
||||
"response_cache_ttl": "1s",
|
||||
},
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2012", // RPC JSON listening address
|
||||
"rpc_gob": ":2013", // RPC GOB listening address
|
||||
"http": ":2080", // HTTP listening address
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
},
|
||||
|
||||
@@ -20,13 +24,11 @@
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
},
|
||||
|
||||
"sm_generic": {
|
||||
"enabled": true,
|
||||
"rater": "internal",
|
||||
"cdrs": "internal",
|
||||
"session_ttl": "50ms",
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
@@ -6,77 +6,18 @@
|
||||
// This file contains the default configuration hardcoded into CGRateS.
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
//"general": {
|
||||
// "http_skip_tls_verify": false, // if enabled Http Client will accept any TLS certificate
|
||||
// "rounding_decimals": 5, // system level precision for floats
|
||||
// "dbdata_encoding": "msgpack", // encoding used to store object data in strings: <msgpack|json>
|
||||
// "tpexport_dir": "/var/log/cgrates/tpe", // path towards export folder for offline Tariff Plans
|
||||
// "http_failed_dir": "/var/log/cgrates/http_failed", // directory path where we store failed http requests
|
||||
// "default_reqtype": "*rated", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
// "default_category": "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
|
||||
// "default_timezone": "Local", // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
// "connect_attempts": 3, // initial server connect attempts
|
||||
// "reconnects": -1, // number of retries in case of connection lost
|
||||
// "response_cache_ttl": "3s", // the life span of a cached response
|
||||
// "internal_ttl": "2m", // maximum duration to wait for internal connections before giving up
|
||||
//},
|
||||
|
||||
|
||||
//"listen": {
|
||||
// "rpc_json": "127.0.0.1:2012", // RPC JSON listening address
|
||||
// "rpc_gob": "127.0.0.1:2013", // RPC GOB listening address
|
||||
// "http": "127.0.0.1:2080", // HTTP listening address
|
||||
//},
|
||||
|
||||
|
||||
//"tariffplan_db": { // database used to store active tariff plan configuration
|
||||
// "db_type": "redis", // tariffplan_db type: <redis>
|
||||
// "db_host": "127.0.0.1", // tariffplan_db host address
|
||||
// "db_port": 6379, // port to reach the tariffplan_db
|
||||
// "db_name": "10", // tariffplan_db name to connect to
|
||||
// "db_user": "", // sername to use when connecting to tariffplan_db
|
||||
// "db_passwd": "", // password to use when connecting to tariffplan_db
|
||||
//},
|
||||
|
||||
|
||||
//"data_db": { // database used to store runtime data (eg: accounts, cdr stats)
|
||||
// "db_type": "redis", // data_db type: <redis>
|
||||
// "db_host": "127.0.0.1", // data_db host address
|
||||
// "db_port": 6379, // data_db port to reach the database
|
||||
// "db_name": "11", // data_db database name to connect to
|
||||
// "db_user": "", // username to use when connecting to data_db
|
||||
// "db_passwd": "", // password to use when connecting to data_db
|
||||
// "load_history_size": 10, // Number of records in the load history
|
||||
//},
|
||||
|
||||
|
||||
//"stor_db": { // database used to store offline tariff plans and CDRs
|
||||
// "db_type": "mysql", // stor database type to use: <mysql|postgres>
|
||||
// "db_host": "127.0.0.1", // the host to connect to
|
||||
// "db_port": 3306, // the port to reach the stordb
|
||||
// "db_name": "cgrates", // stor database name
|
||||
// "db_user": "cgrates", // username to use when connecting to stordb
|
||||
// "db_passwd": "CGRateS.org", // password to use when connecting to stordb
|
||||
// "max_open_conns": 100, // maximum database connections opened
|
||||
// "max_idle_conns": 10, // maximum database connections idle
|
||||
//},
|
||||
|
||||
|
||||
//"balancer": {
|
||||
// "enabled": false, // start Balancer service: <true|false>
|
||||
//},
|
||||
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
// "balancer": "", // register to balancer as worker: <""|internal|x.y.z.y:1234>
|
||||
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality: <""|internal|x.y.z.y:1234>
|
||||
// "historys": "", // address where to reach the history service, empty to disable history functionality: <""|internal|x.y.z.y:1234>
|
||||
// "pubsubs": "", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
|
||||
"users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
|
||||
"aliases": "internal", // address where to reach the aliases service, empty to disable aliases functionality: <""|internal|x.y.z.y:1234>
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"users_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"aliases_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
@@ -87,168 +28,19 @@
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
// "extra_fields": [], // extra fields to store in CDRs for non-generic CDRs
|
||||
// "store_cdrs": true, // store cdrs in storDb
|
||||
// "rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
// "pubsubs": "", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
|
||||
// "users": "", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
|
||||
// "aliases": "", // address where to reach the aliases service, empty to disable aliases functionality: <""|internal|x.y.z.y:1234>
|
||||
// "cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
// "cdr_replication":[], // replicate the raw CDR to a number of servers
|
||||
},
|
||||
|
||||
|
||||
"cdrstats": {
|
||||
"enabled": true, // starts the cdrstats service: <true|false>
|
||||
// "save_interval": "1m", // interval to save changed stats into dataDb storage
|
||||
},
|
||||
|
||||
|
||||
//"cdre": {
|
||||
// "*default": {
|
||||
// "cdr_format": "csv", // exported CDRs format <csv>
|
||||
// "field_separator": ",",
|
||||
// "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes)
|
||||
// "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems)
|
||||
// "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems)
|
||||
// "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
|
||||
// "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding
|
||||
// "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents)
|
||||
// "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export
|
||||
// "mask_length": 0, // length of the destination suffix to be masked
|
||||
// "export_dir": "/var/log/cgrates/cdre", // path where the exported CDRs will be placed
|
||||
// "header_fields": [], // template of the exported header fields
|
||||
// "content_fields": [ // template of the exported content fields
|
||||
// {"tag": "CgrId", "cdr_field_id": "CgrId", "type": "cdrfield", "value": "CgrId"},
|
||||
// {"tag":"RunId", "cdr_field_id": "MediationRunId", "type": "cdrfield", "value": "MediationRunId"},
|
||||
// {"tag":"Tor", "cdr_field_id": "TOR", "type": "cdrfield", "value": "TOR"},
|
||||
// {"tag":"AccId", "cdr_field_id": "AccId", "type": "cdrfield", "value": "AccId"},
|
||||
// {"tag":"ReqType", "cdr_field_id": "ReqType", "type": "cdrfield", "value": "ReqType"},
|
||||
// {"tag":"Direction", "cdr_field_id": "Direction", "type": "cdrfield", "value": "Direction"},
|
||||
// {"tag":"Tenant", "cdr_field_id": "Tenant", "type": "cdrfield", "value": "Tenant"},
|
||||
// {"tag":"Category", "cdr_field_id": "Category", "type": "cdrfield", "value": "Category"},
|
||||
// {"tag":"Account", "cdr_field_id": "Account", "type": "cdrfield", "value": "Account"},
|
||||
// {"tag":"Subject", "cdr_field_id": "Subject", "type": "cdrfield", "value": "Subject"},
|
||||
// {"tag":"Destination", "cdr_field_id": "Destination", "type": "cdrfield", "value": "Destination"},
|
||||
// {"tag":"SetupTime", "cdr_field_id": "SetupTime", "type": "cdrfield", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
// {"tag":"AnswerTime", "cdr_field_id": "AnswerTime", "type": "cdrfield", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"},
|
||||
// {"tag":"Usage", "cdr_field_id": "Usage", "type": "cdrfield", "value": "Usage"},
|
||||
// {"tag":"Cost", "cdr_field_id": "Cost", "type": "cdrfield", "value": "Cost"},
|
||||
// ],
|
||||
// "trailer_fields": [], // template of the exported trailer fields
|
||||
// }
|
||||
//},
|
||||
|
||||
|
||||
//"cdrc": {
|
||||
// "*default": {
|
||||
// "enabled": false, // enable CDR client functionality
|
||||
// "dry_run": false, // do not send the CDRs to CDRS, just parse them
|
||||
// "cdrs": "internal", // address where to reach CDR server. <internal|x.y.z.y:1234>
|
||||
// "cdr_format": "csv", // CDR file format <csv|freeswitch_csv|fwv|opensips_flatstore>
|
||||
// "field_separator": ",", // separator used in case of csv files
|
||||
// "timezone": "", // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
// "run_delay": 0, // sleep interval in seconds between consecutive runs, 0 to use automation via inotify
|
||||
// "max_open_files": 1024, // maximum simultaneous files to process, 0 for unlimited
|
||||
// "data_usage_multiply_factor": 1024, // conversion factor for data usage
|
||||
// "cdr_in_dir": "/var/log/cgrates/cdrc/in", // absolute path towards the directory where the CDRs are stored
|
||||
// "cdr_out_dir": "/var/log/cgrates/cdrc/out", // absolute path towards the directory where processed CDRs will be moved
|
||||
// "failed_calls_prefix": "missed_calls", // used in case of flatstore CDRs to avoid searching for BYE records
|
||||
// "cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database
|
||||
// "cdr_filter": "", // filter CDR records to import
|
||||
// "partial_record_cache": "10s", // duration to cache partial records when not pairing
|
||||
// "header_fields": [], // template of the import header fields
|
||||
// "content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
|
||||
// {"tag": "tor", "cdr_field_id": "TOR", "type": "cdrfield", "value": "2", "mandatory": true},
|
||||
// {"tag": "accid", "cdr_field_id": "AccId", "type": "cdrfield", "value": "3", "mandatory": true},
|
||||
// {"tag": "reqtype", "cdr_field_id": "ReqType", "type": "cdrfield", "value": "4", "mandatory": true},
|
||||
// {"tag": "direction", "cdr_field_id": "Direction", "type": "cdrfield", "value": "5", "mandatory": true},
|
||||
// {"tag": "tenant", "cdr_field_id": "Tenant", "type": "cdrfield", "value": "6", "mandatory": true},
|
||||
// {"tag": "category", "cdr_field_id": "Category", "type": "cdrfield", "value": "7", "mandatory": true},
|
||||
// {"tag": "account", "cdr_field_id": "Account", "type": "cdrfield", "value": "8", "mandatory": true},
|
||||
// {"tag": "subject", "cdr_field_id": "Subject", "type": "cdrfield", "value": "9", "mandatory": true},
|
||||
// {"tag": "destination", "cdr_field_id": "Destination", "type": "cdrfield", "value": "10", "mandatory": true},
|
||||
// {"tag": "setup_time", "cdr_field_id": "SetupTime", "type": "cdrfield", "value": "11", "mandatory": true},
|
||||
// {"tag": "answer_time", "cdr_field_id": "AnswerTime", "type": "cdrfield", "value": "12", "mandatory": true},
|
||||
// {"tag": "usage", "cdr_field_id": "Usage", "type": "cdrfield", "value": "13", "mandatory": true},
|
||||
// ],
|
||||
// "trailer_fields": [], // template of the import trailer fields
|
||||
// }
|
||||
//},
|
||||
|
||||
"sm_generic": {
|
||||
"enabled": true, // starts SessionManager service: <true|false>
|
||||
// "listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests
|
||||
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
// "cdrs": "internal", // address where to reach CDR Server <""|internal|x.y.z.y:1234>
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
},
|
||||
|
||||
|
||||
//"sm_freeswitch": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
// "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
|
||||
// "create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
// "extra_fields": [], // extra fields to store in auth/CDRs when creating them
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "min_dur_low_balance": "5s", // threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval)
|
||||
// "low_balance_ann_file": "", // file to be played when low balance is reached for prepaid calls
|
||||
// "empty_balance_context": "", // if defined, prepaid calls will be transfered to this context on empty balance
|
||||
// "empty_balance_ann_file": "", // file to be played before disconnecting prepaid calls on empty balance (applies only if no context defined)
|
||||
// "subscribe_park": true, // subscribe via fsock to receive park events
|
||||
// "channel_sync_interval": "5m", // sync channels with freeswitch regularly
|
||||
// "connections":[ // instantiate connections to multiple FreeSWITCH servers
|
||||
// {"server": "127.0.0.1:8021", "password": "ClueCon", "reconnects": 5}
|
||||
// ],
|
||||
//},
|
||||
|
||||
|
||||
//"sm_kamailio": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
// "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
|
||||
// "create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "connections":[ // instantiate connections to multiple Kamailio servers
|
||||
// {"evapi_addr": "127.0.0.1:8448", "reconnects": 5}
|
||||
// ],
|
||||
//},
|
||||
|
||||
|
||||
//"sm_opensips": {
|
||||
// "enabled": false, // starts SessionManager service: <true|false>
|
||||
// "listen_udp": "127.0.0.1:2020", // address where to listen for datagram events coming from OpenSIPS
|
||||
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
|
||||
// "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
|
||||
// "reconnects": 5, // number of reconnects if connection is lost
|
||||
// "create_cdr": false, // create CDR out of events and sends them to CDRS component
|
||||
// "debit_interval": "10s", // interval to perform debits on.
|
||||
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
|
||||
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
|
||||
// "events_subscribe_interval": "60s", // automatic events subscription to OpenSIPS, 0 to disable it
|
||||
// "mi_addr": "127.0.0.1:8020", // address where to reach OpenSIPS MI to send session disconnects
|
||||
//},
|
||||
|
||||
|
||||
//"historys": {
|
||||
// "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
|
||||
//},
|
||||
|
||||
|
||||
//"pubsubs": {
|
||||
// "enabled": false, // starts PubSub service: <true|false>.
|
||||
//},
|
||||
|
||||
|
||||
"aliases": {
|
||||
"enabled": true, // starts Aliases service: <true|false>.
|
||||
},
|
||||
@@ -256,45 +48,7 @@
|
||||
|
||||
"users": {
|
||||
"enabled": true, // starts User service: <true|false>.
|
||||
// "indexes": [], // user profile field indexes
|
||||
},
|
||||
|
||||
|
||||
//"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
|
||||
//},
|
||||
|
||||
|
||||
//"suretax": {
|
||||
// "url": "", // API url
|
||||
// "client_number": "", // client number, provided by SureTax
|
||||
// "validation_key": "", // validation key provided by SureTax
|
||||
// "business_unit": "", // client’s Business Unit
|
||||
// "timezone": "Local", // convert the time of the events to this timezone before sending request out <UTC|Local|$IANA_TZ_DB>
|
||||
// "include_local_cost": false, // sum local calculated cost with tax one in final cost
|
||||
// "return_file_code": "0", // default or Quote purposes <0|Q>
|
||||
// "response_group": "03", // determines how taxes are grouped for the response <03|13>
|
||||
// "response_type": "D4", // determines the granularity of taxes and (optionally) the decimal precision for the tax calculations and amounts in the response
|
||||
// "regulatory_code": "03", // provider type
|
||||
// "client_tracking": "CgrId", // template extracting client information out of StoredCdr; <$RSRFields>
|
||||
// "customer_number": "Subject", // template extracting customer number out of StoredCdr; <$RSRFields>
|
||||
// "orig_number": "Subject", // template extracting origination number out of StoredCdr; <$RSRFields>
|
||||
// "term_number": "Destination", // template extracting termination number out of StoredCdr; <$RSRFields>
|
||||
// "bill_to_number": "", // template extracting billed to number out of StoredCdr; <$RSRFields>
|
||||
// "zipcode": "", // template extracting billing zip code out of StoredCdr; <$RSRFields>
|
||||
// "plus4": "", // template extracting billing zip code extension out of StoredCdr; <$RSRFields>
|
||||
// "p2pzipcode": "", // template extracting secondary zip code out of StoredCdr; <$RSRFields>
|
||||
// "p2pplus4": "", // template extracting secondary zip code extension out of StoredCdr; <$RSRFields>
|
||||
// "units": "^1", // template extracting number of “lines” or unique charges contained within the revenue out of StoredCdr; <$RSRFields>
|
||||
// "unit_type": "^00", // template extracting number of unique access lines out of StoredCdr; <$RSRFields>
|
||||
// "tax_included": "^0", // template extracting tax included in revenue out of StoredCdr; <$RSRFields>
|
||||
// "tax_situs_rule": "^04", // template extracting tax situs rule out of StoredCdr; <$RSRFields>
|
||||
// "trans_type_code": "^010101", // template extracting transaction type indicator out of StoredCdr; <$RSRFields>
|
||||
// "sales_type_code": "^R", // template extracting sales type code out of StoredCdr; <$RSRFields>
|
||||
// "tax_exemption_code_list": "", // template extracting tax exemption code list out of StoredCdr; <$RSRFields>
|
||||
//},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,17 @@
|
||||
"http": ":2080", // HTTP listening address
|
||||
},
|
||||
|
||||
"rater": {
|
||||
"rals": {
|
||||
"enabled": true, // enable Rater service: <true|false>
|
||||
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
"pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
|
||||
"users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"users_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
@@ -23,8 +29,9 @@
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
|
||||
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"cdrstats": {
|
||||
|
||||
@@ -36,6 +36,15 @@
|
||||
<rule avp="Recipient-Address" required="false" max="1" />
|
||||
</data>
|
||||
</avp>
|
||||
<avp name="TransactionId" code="29001" must="V" may="P,M" must-not="-" may-encrypt="N" vendor-id="2011">
|
||||
<data type="OctetString"/>
|
||||
</avp>
|
||||
<avp name="MC-Service-Id" code="29002" must="V" may="P,M" must-not="-" may-encrypt="N" vendor-id="2011">
|
||||
<data type="UTF8String"/>
|
||||
</avp>
|
||||
<avp name="TransparentData" code="29003" must="V" may="P,M" must-not="-" may-encrypt="N" vendor-id="2011">
|
||||
<data type="UTF8String"/>
|
||||
</avp>
|
||||
<avp name="CallingPartyAddress" code="20336" must="V" may="P,M" must-not="-" may-encrypt="N" vendor-id="2011">
|
||||
<data type="UTF8String" />
|
||||
</avp>
|
||||
@@ -133,7 +142,7 @@
|
||||
<avp name="Re-Routing-Number" code="20937" must="V" may="P,M" must-not="-" may-encrypt="N" vendor-id="2011">
|
||||
<data type="UTF8String" />
|
||||
</avp>
|
||||
<avp name="HighLayerCharacteristics" code="29001" must="V" may="P,M" must-not="-" may-encrypt="N" vendor-id="2011">
|
||||
<avp name="HighLayerCharacteristics" code="20938" must="V" may="P,M" must-not="-" may-encrypt="N" vendor-id="2011">
|
||||
<data type="OctetString" />
|
||||
</avp>
|
||||
<avp name="MC-Service-Id" code="29002" must="V" may="P,M" must-not="-" may-encrypt="N" vendor-id="2011">
|
||||
@@ -143,4 +152,4 @@
|
||||
<data type="UTF8String" />
|
||||
</avp>
|
||||
</application>
|
||||
</diameter>
|
||||
</diameter>
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
<avp name="Time-Of-First-Usage" code="263" must="M,V" may="-" must-not="-" may-encrypt="Y" vendor-id="12645">
|
||||
<data type="Time" />
|
||||
</avp>
|
||||
<avp name="Time-Of-Last-Usage" code="266" must="M,V" may="-" must-not="-" may-encrypt="Y" vendor-id="12645">
|
||||
<avp name="Time-Of-Last-Usage" code="264" must="M,V" may="-" must-not="-" may-encrypt="Y" vendor-id="12645">
|
||||
<data type="Time" />
|
||||
</avp>
|
||||
</application>
|
||||
</diameter>
|
||||
</diameter>
|
||||
|
||||
@@ -17,7 +17,7 @@ RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927
|
||||
RUN echo 'deb http://repo.mongodb.org/apt/debian wheezy/mongodb-org/3.2 main' | tee '/etc/apt/sources.list.d/mongodb-org-3.2.list'
|
||||
|
||||
# install dependencies
|
||||
RUN apt-get -y update && apt-get -y install git bzr mercurial redis-server mysql-server python-pycurl python-mysqldb postgresql postgresql-client sudo wget freeswitch-meta-vanilla vim zsh mongodb-org
|
||||
RUN apt-get -y update && apt-get -y install git bzr mercurial redis-server mysql-server python-pycurl python-mysqldb postgresql postgresql-client sudo wget freeswitch-meta-vanilla vim zsh mongodb-org tmux rsyslog ngrep
|
||||
|
||||
# add mongo conf
|
||||
COPY mongod.conf /etc/mongod.conf
|
||||
@@ -26,7 +26,7 @@ COPY mongod.conf /etc/mongod.conf
|
||||
RUN useradd -c CGRateS -d /var/run/cgrates -s /bin/false -r cgrates
|
||||
|
||||
# install golang
|
||||
RUN wget -qO- https://storage.googleapis.com/golang/go1.6.linux-amd64.tar.gz | tar xzf - -C /root/
|
||||
RUN wget -qO- https://storage.googleapis.com/golang/go1.6.2.linux-amd64.tar.gz | tar xzf - -C /root/
|
||||
|
||||
#install glide
|
||||
RUN GOROOT=/root/go GOPATH=/root/code /root/go/bin/go get github.com/Masterminds/glide
|
||||
@@ -34,6 +34,9 @@ RUN GOROOT=/root/go GOPATH=/root/code /root/go/bin/go get github.com/Masterminds
|
||||
#install oh-my-zsh
|
||||
RUN TERM=xterm sh -c "$(wget https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"; exit 0
|
||||
|
||||
# change shell for tmux
|
||||
RUN chsh -s /usr/bin/zsh
|
||||
|
||||
# cleanup
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user