mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-15 05:09:54 +05:00
Merge branch 'master' of https://github.com/cgrates/cgrates
This commit is contained in:
@@ -135,16 +135,6 @@ func RemKey(key string) {
|
||||
delete(cache, key)
|
||||
}
|
||||
|
||||
func RemPrefixKey(prefix string) {
|
||||
mux.Lock()
|
||||
defer mux.Unlock()
|
||||
for key, _ := range cache {
|
||||
if strings.HasPrefix(key, prefix) {
|
||||
delete(cache, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func XRemKey(key string) {
|
||||
xMux.Lock()
|
||||
defer xMux.Unlock()
|
||||
@@ -155,6 +145,17 @@ func XRemKey(key string) {
|
||||
}
|
||||
delete(xcache, key)
|
||||
}
|
||||
|
||||
func RemPrefixKey(prefix string) {
|
||||
mux.Lock()
|
||||
defer mux.Unlock()
|
||||
for key, _ := range cache {
|
||||
if strings.HasPrefix(key, prefix) {
|
||||
delete(cache, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func XRemPrefixKey(prefix string) {
|
||||
xMux.Lock()
|
||||
defer xMux.Unlock()
|
||||
@@ -170,6 +171,26 @@ func XRemPrefixKey(prefix string) {
|
||||
}
|
||||
}
|
||||
|
||||
func GetAllEntries(prefix string) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for key, timestampedValue := range cache {
|
||||
if strings.HasPrefix(key, prefix) {
|
||||
result[key] = timestampedValue.value
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func XGetAllEntries(prefix string) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for key, value := range xcache {
|
||||
if strings.HasPrefix(key, prefix) {
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Delete all keys from expiraton cache
|
||||
func XFlush() {
|
||||
xMux.Lock()
|
||||
|
||||
@@ -34,11 +34,11 @@ const (
|
||||
INBOUND = "*in"
|
||||
OUTBOUND = "*out"
|
||||
// Balance types
|
||||
CREDIT = "*monetary"
|
||||
SMS = "*sms"
|
||||
TRAFFIC = "*internet"
|
||||
TRAFFIC_TIME = "*internet_time"
|
||||
MINUTES = "*minutes"
|
||||
CREDIT = "*monetary"
|
||||
SMS = "*sms"
|
||||
DATA = "*data"
|
||||
DATA_TIME = "*data_time"
|
||||
MINUTES = "*minutes"
|
||||
// action price type
|
||||
PRICE_PERCENT = "*percent"
|
||||
PRICE_ABSOLUTE = "*absolute"
|
||||
@@ -310,15 +310,6 @@ func (ub *Account) refundIncrement(increment *Increment, direction string, count
|
||||
}
|
||||
}
|
||||
|
||||
// Debits some amount of user's specified balance. Returns the remaining credit in user's balance.
|
||||
func (ub *Account) debitGenericBalance(balanceId string, direction string, amount float64, count bool) float64 {
|
||||
if count {
|
||||
ub.countUnits(&Action{BalanceType: balanceId, Direction: direction, Balance: &Balance{Value: amount}})
|
||||
}
|
||||
ub.BalanceMap[balanceId+direction].Debit(amount)
|
||||
return ub.BalanceMap[balanceId+direction].GetTotalValue()
|
||||
}
|
||||
|
||||
// Scans the action trigers and execute the actions for which trigger is met
|
||||
func (ub *Account) executeActionTriggers(a *Action) {
|
||||
ub.ActionTriggers.Sort()
|
||||
|
||||
@@ -157,47 +157,6 @@ func TestAccountStorageStore(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitMoneyBalance(t *testing.T) {
|
||||
b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"}
|
||||
b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}}}
|
||||
result := rifsBalance.debitGenericBalance(CREDIT, OUTBOUND, 6, false)
|
||||
if rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != 15 || result != rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value {
|
||||
t.Errorf("Expected %v was %v", 15, rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitAllMoneyBalance(t *testing.T) {
|
||||
b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"}
|
||||
b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}}}
|
||||
rifsBalance.debitGenericBalance(CREDIT, OUTBOUND, 21, false)
|
||||
result := rifsBalance.debitGenericBalance(CREDIT, OUTBOUND, 0, false)
|
||||
if rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != 0 || result != rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value {
|
||||
t.Errorf("Expected %v was %v", 0, rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitMoreMoneyBalance(t *testing.T) {
|
||||
b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"}
|
||||
b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}}}
|
||||
result := rifsBalance.debitGenericBalance(CREDIT, OUTBOUND, 22, false)
|
||||
if rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != -1 || result != rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value {
|
||||
t.Errorf("Expected %v was %v", -1, rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitNegativeMoneyBalance(t *testing.T) {
|
||||
b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"}
|
||||
b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}}}
|
||||
result := rifsBalance.debitGenericBalance(CREDIT, OUTBOUND, -15, false)
|
||||
if rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value != 36 || result != rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value {
|
||||
t.Errorf("Expected %v was %v", 36, rifsBalance.BalanceMap[CREDIT+OUTBOUND][0].Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitCreditZeroSecond(t *testing.T) {
|
||||
b1 := &Balance{Uuid: "testb", Value: 10, Weight: 10, DestinationId: "NAT", RateSubject: "*zero1s"}
|
||||
cc := &CallCost{
|
||||
@@ -791,51 +750,11 @@ func TestDebitCreditSubjectMixedPartPay(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitSMSBalance(t *testing.T) {
|
||||
b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"}
|
||||
b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}, SMS + OUTBOUND: BalanceChain{&Balance{Value: 100}}}}
|
||||
result := rifsBalance.debitGenericBalance(SMS, OUTBOUND, 12, false)
|
||||
if rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value != 88 || result != rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value {
|
||||
t.Errorf("Expected %v was %v", 88, rifsBalance.BalanceMap[SMS+OUTBOUND])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitAllSMSBalance(t *testing.T) {
|
||||
b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"}
|
||||
b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}, SMS + OUTBOUND: BalanceChain{&Balance{Value: 100}}}}
|
||||
result := rifsBalance.debitGenericBalance(SMS, OUTBOUND, 100, false)
|
||||
if rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value != 0 || result != rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value {
|
||||
t.Errorf("Expected %v was %v", 0, rifsBalance.BalanceMap[SMS+OUTBOUND])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitMoreSMSBalance(t *testing.T) {
|
||||
b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"}
|
||||
b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}, SMS + OUTBOUND: BalanceChain{&Balance{Value: 100}}}}
|
||||
result := rifsBalance.debitGenericBalance(SMS, OUTBOUND, 110, false)
|
||||
if rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value != -10 || result != rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value {
|
||||
t.Errorf("Expected %v was %v", -10, rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitNegativeSMSBalance(t *testing.T) {
|
||||
b1 := &Balance{Value: 10, Weight: 10, DestinationId: "NAT"}
|
||||
b2 := &Balance{Value: 100, Weight: 20, DestinationId: "RET"}
|
||||
rifsBalance := &Account{Id: "other", BalanceMap: map[string]BalanceChain{MINUTES + OUTBOUND: BalanceChain{b1, b2}, CREDIT + OUTBOUND: BalanceChain{&Balance{Value: 21}}, SMS + OUTBOUND: BalanceChain{&Balance{Value: 100}}}}
|
||||
result := rifsBalance.debitGenericBalance(SMS, OUTBOUND, -15, false)
|
||||
if rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value != 115 || result != rifsBalance.BalanceMap[SMS+OUTBOUND][0].Value {
|
||||
t.Errorf("Expected %v was %v", 115, rifsBalance.BalanceMap[SMS+OUTBOUND])
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccountdebitBalance(t *testing.T) {
|
||||
ub := &Account{
|
||||
Id: "rif",
|
||||
AllowNegative: true,
|
||||
BalanceMap: map[string]BalanceChain{SMS: BalanceChain{&Balance{Value: 14}}, TRAFFIC: BalanceChain{&Balance{Value: 1204}}, MINUTES + OUTBOUND: BalanceChain{&Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}},
|
||||
BalanceMap: map[string]BalanceChain{SMS: BalanceChain{&Balance{Value: 14}}, DATA: BalanceChain{&Balance{Value: 1204}}, MINUTES + OUTBOUND: BalanceChain{&Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}},
|
||||
}
|
||||
newMb := &Balance{Weight: 20, DestinationId: "NEW"}
|
||||
a := &Action{BalanceType: MINUTES, Direction: OUTBOUND, Balance: newMb}
|
||||
@@ -850,7 +769,7 @@ func TestAccountdebitBalanceExists(t *testing.T) {
|
||||
ub := &Account{
|
||||
Id: "rif",
|
||||
AllowNegative: true,
|
||||
BalanceMap: map[string]BalanceChain{SMS + OUTBOUND: BalanceChain{&Balance{Value: 14}}, TRAFFIC + OUTBOUND: BalanceChain{&Balance{Value: 1024}}, MINUTES + OUTBOUND: BalanceChain{&Balance{Value: 15, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}},
|
||||
BalanceMap: map[string]BalanceChain{SMS + OUTBOUND: BalanceChain{&Balance{Value: 14}}, DATA + OUTBOUND: BalanceChain{&Balance{Value: 1024}}, MINUTES + OUTBOUND: BalanceChain{&Balance{Value: 15, Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}},
|
||||
}
|
||||
newMb := &Balance{Value: -10, Weight: 20, DestinationId: "NAT"}
|
||||
a := &Action{BalanceType: MINUTES, Direction: OUTBOUND, Balance: newMb}
|
||||
@@ -864,7 +783,7 @@ func TestAccountAddMinuteNil(t *testing.T) {
|
||||
ub := &Account{
|
||||
Id: "rif",
|
||||
AllowNegative: true,
|
||||
BalanceMap: map[string]BalanceChain{SMS + OUTBOUND: BalanceChain{&Balance{Value: 14}}, TRAFFIC + OUTBOUND: BalanceChain{&Balance{Value: 1024}}, MINUTES + OUTBOUND: BalanceChain{&Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}},
|
||||
BalanceMap: map[string]BalanceChain{SMS + OUTBOUND: BalanceChain{&Balance{Value: 14}}, DATA + OUTBOUND: BalanceChain{&Balance{Value: 1024}}, MINUTES + OUTBOUND: BalanceChain{&Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}},
|
||||
}
|
||||
ub.debitBalanceAction(nil)
|
||||
if len(ub.BalanceMap[MINUTES+OUTBOUND]) != 2 {
|
||||
|
||||
@@ -112,11 +112,11 @@ type CallDescriptor struct {
|
||||
TimeStart, TimeEnd time.Time
|
||||
LoopIndex float64 // indicates the position of this segment in a cost request loop
|
||||
CallDuration time.Duration // the call duration so far (till TimeEnd)
|
||||
Amount float64
|
||||
FallbackSubject string // the subject to check for destination if not found on primary subject
|
||||
RatingInfos RatingInfos
|
||||
Increments Increments
|
||||
account *Account
|
||||
//Amount float64
|
||||
FallbackSubject string // the subject to check for destination if not found on primary subject
|
||||
RatingInfos RatingInfos
|
||||
Increments Increments
|
||||
account *Account
|
||||
}
|
||||
|
||||
func (cd *CallDescriptor) ValidateCallData() error {
|
||||
@@ -609,60 +609,6 @@ func (cd *CallDescriptor) RefundIncrements() (left float64, err error) {
|
||||
return 0.0, err
|
||||
}
|
||||
|
||||
/*
|
||||
Interface method used to add/substract an amount of cents from user's money balance.
|
||||
The amount filed has to be filled in call descriptor.
|
||||
*/
|
||||
func (cd *CallDescriptor) DebitCents() (left float64, err error) {
|
||||
if userBalance, err := cd.getAccount(); err == nil && userBalance != nil {
|
||||
defer accountingStorage.SetAccount(userBalance)
|
||||
return userBalance.debitGenericBalance(CREDIT, cd.Direction, cd.Amount, true), nil
|
||||
}
|
||||
return 0.0, err
|
||||
}
|
||||
|
||||
/*
|
||||
Interface method used to add/substract an amount of units from user's sms balance.
|
||||
The amount filed has to be filled in call descriptor.
|
||||
*/
|
||||
func (cd *CallDescriptor) DebitSMS() (left float64, err error) {
|
||||
if userBalance, err := cd.getAccount(); err == nil && userBalance != nil {
|
||||
defer accountingStorage.SetAccount(userBalance)
|
||||
return userBalance.debitGenericBalance(SMS, cd.Direction, cd.Amount, true), nil
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
/*
|
||||
Interface method used to add/substract an amount of seconds from user's minutes balance.
|
||||
The amount filed has to be filled in call descriptor.
|
||||
*/
|
||||
func (cd *CallDescriptor) DebitSeconds() (err error) {
|
||||
if userBalance, err := cd.getAccount(); err == nil && userBalance != nil {
|
||||
defer accountingStorage.SetAccount(userBalance)
|
||||
return userBalance.debitCreditBalance(cd.CreateCallCost(), true)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
Adds the specified amount of seconds to the received call seconds. When the threshold specified
|
||||
in the user's tariff plan is reached then the received call balance is reseted and the bonus
|
||||
specified in the tariff plan is applied.
|
||||
The amount filed has to be filled in call descriptor.
|
||||
*/
|
||||
func (cd *CallDescriptor) AddRecievedCallSeconds() (err error) {
|
||||
if userBalance, err := cd.getAccount(); err == nil && userBalance != nil {
|
||||
a := &Action{
|
||||
Direction: INBOUND,
|
||||
Balance: &Balance{Value: cd.Amount, DestinationId: cd.Destination},
|
||||
}
|
||||
userBalance.countUnits(a)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (cd *CallDescriptor) FlushCache() (err error) {
|
||||
cache2go.XFlush()
|
||||
cache2go.Flush()
|
||||
@@ -686,17 +632,17 @@ func (cd *CallDescriptor) CreateCallCost() *CallCost {
|
||||
|
||||
func (cd *CallDescriptor) Clone() *CallDescriptor {
|
||||
return &CallDescriptor{
|
||||
Direction: cd.Direction,
|
||||
TOR: cd.TOR,
|
||||
Tenant: cd.Tenant,
|
||||
Subject: cd.Subject,
|
||||
Account: cd.Account,
|
||||
Destination: cd.Destination,
|
||||
TimeStart: cd.TimeStart,
|
||||
TimeEnd: cd.TimeEnd,
|
||||
LoopIndex: cd.LoopIndex,
|
||||
CallDuration: cd.CallDuration,
|
||||
Amount: cd.Amount,
|
||||
Direction: cd.Direction,
|
||||
TOR: cd.TOR,
|
||||
Tenant: cd.Tenant,
|
||||
Subject: cd.Subject,
|
||||
Account: cd.Account,
|
||||
Destination: cd.Destination,
|
||||
TimeStart: cd.TimeStart,
|
||||
TimeEnd: cd.TimeEnd,
|
||||
LoopIndex: cd.LoopIndex,
|
||||
CallDuration: cd.CallDuration,
|
||||
// Amount: cd.Amount,
|
||||
FallbackSubject: cd.FallbackSubject,
|
||||
//RatingInfos: cd.RatingInfos,
|
||||
//Increments: cd.Increments,
|
||||
|
||||
@@ -425,7 +425,7 @@ func TestMaxSessionTimeWithAccountAccount(t *testing.T) {
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
Destination: "0723",
|
||||
Amount: 1000}
|
||||
}
|
||||
result, err := cd.GetMaxSessionDuration()
|
||||
expected := time.Minute
|
||||
if result != expected || err != nil {
|
||||
@@ -442,7 +442,7 @@ func TestMaxSessionTimeNoCredit(t *testing.T) {
|
||||
Tenant: "vdf",
|
||||
Subject: "broker",
|
||||
Destination: "0723",
|
||||
Amount: 5400}
|
||||
}
|
||||
result, err := cd.GetMaxSessionDuration()
|
||||
if result != time.Minute || err != nil {
|
||||
t.Errorf("Expected %v was %v", time.Minute, result)
|
||||
@@ -462,7 +462,7 @@ func TestMaxSessionModifiesCallDesc(t *testing.T) {
|
||||
Account: "minu",
|
||||
Destination: "0723",
|
||||
CallDuration: t2.Sub(t1),
|
||||
Amount: 5400}
|
||||
}
|
||||
initial := cd.Clone()
|
||||
cd.GetMaxSessionDuration()
|
||||
cd.account = nil // it's OK to cache the account
|
||||
@@ -481,7 +481,7 @@ func TestMaxDebitDurationNoGreatherThanInitialDuration(t *testing.T) {
|
||||
Subject: "minu_from_tm",
|
||||
Account: "minu",
|
||||
Destination: "0723",
|
||||
Amount: 1000}
|
||||
}
|
||||
initialDuration := cd.TimeEnd.Sub(cd.TimeStart)
|
||||
result, _ := cd.GetMaxSessionDuration()
|
||||
if result > initialDuration {
|
||||
@@ -671,7 +671,7 @@ func BenchmarkSplitting(b *testing.B) {
|
||||
|
||||
func BenchmarkStorageSingleGetSessionTime(b *testing.B) {
|
||||
b.StopTimer()
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "minutosu", Destination: "0723", Amount: 100}
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "minutosu", Destination: "0723"}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetMaxSessionDuration()
|
||||
@@ -680,7 +680,7 @@ func BenchmarkStorageSingleGetSessionTime(b *testing.B) {
|
||||
|
||||
func BenchmarkStorageMultipleGetSessionTime(b *testing.B) {
|
||||
b.StopTimer()
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "minutosu", Destination: "0723", Amount: 5400}
|
||||
cd := &CallDescriptor{Direction: "*out", TOR: "0", Tenant: "vdf", Subject: "minutosu", Destination: "0723"}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetMaxSessionDuration()
|
||||
|
||||
@@ -20,9 +20,11 @@ package engine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/cgrates/cgrates/cache2go"
|
||||
"strings"
|
||||
|
||||
"github.com/cgrates/cgrates/cache2go"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
|
||||
"github.com/cgrates/cgrates/history"
|
||||
)
|
||||
|
||||
@@ -81,3 +83,26 @@ func CachedDestHasPrefix(destId, prefix string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func CleanStalePrefixes(destIds []string) {
|
||||
prefixMap := cache2go.GetAllEntries(DESTINATION_PREFIX)
|
||||
for prefix, idIDs := range prefixMap {
|
||||
dIDs := idIDs.([]string)
|
||||
changed := false
|
||||
for _, searchedDID := range destIds {
|
||||
if found, i := utils.GetSliceMemberIndex(dIDs, searchedDID); found {
|
||||
if len(dIDs) == 1 {
|
||||
// remove de prefix from cache
|
||||
cache2go.RemKey(prefix)
|
||||
} else {
|
||||
// delte the testination from list and put the new list in chache
|
||||
dIDs[i], dIDs = dIDs[len(dIDs)-1], dIDs[:len(dIDs)-1]
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
cache2go.Cache(prefix, dIDs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,22 @@ func TestNonCachedDestWrongPrefix(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanStalePrefixes(t *testing.T) {
|
||||
cache2go.Cache(DESTINATION_PREFIX+"1", []string{"D1", "D2"})
|
||||
cache2go.Cache(DESTINATION_PREFIX+"2", []string{"D1"})
|
||||
cache2go.Cache(DESTINATION_PREFIX+"3", []string{"D2"})
|
||||
CleanStalePrefixes([]string{"D1"})
|
||||
if r, err := cache2go.GetCached(DESTINATION_PREFIX + "1"); err != nil || len(r.([]string)) != 1 {
|
||||
t.Error("Error cleaning stale destination ids", r)
|
||||
}
|
||||
if r, err := cache2go.GetCached(DESTINATION_PREFIX + "2"); err == nil {
|
||||
t.Error("Error removing stale prefix: ", r)
|
||||
}
|
||||
if r, err := cache2go.GetCached(DESTINATION_PREFIX + "3"); err != nil || len(r.([]string)) != 1 {
|
||||
t.Error("Error performing stale cleaning: ", r)
|
||||
}
|
||||
}
|
||||
|
||||
/********************************* Benchmarks **********************************/
|
||||
|
||||
func BenchmarkDestinationStorageStoreRestore(b *testing.B) {
|
||||
|
||||
@@ -495,7 +495,6 @@ func TestLoadDestinationRateTimings(t *testing.T) {
|
||||
},
|
||||
Ratings: map[string]*RIRate{
|
||||
"d54545c1": &RIRate{
|
||||
Id: "R1",
|
||||
ConnectFee: 0,
|
||||
Rates: []*Rate{
|
||||
&Rate{
|
||||
@@ -509,7 +508,6 @@ func TestLoadDestinationRateTimings(t *testing.T) {
|
||||
RoundingDecimals: 2,
|
||||
},
|
||||
"4bb00b9c": &RIRate{
|
||||
Id: "R2",
|
||||
ConnectFee: 0,
|
||||
Rates: []*Rate{
|
||||
&Rate{
|
||||
@@ -523,7 +521,6 @@ func TestLoadDestinationRateTimings(t *testing.T) {
|
||||
RoundingDecimals: 2,
|
||||
},
|
||||
"e06c337f": &RIRate{
|
||||
Id: "R3",
|
||||
ConnectFee: 0,
|
||||
Rates: []*Rate{
|
||||
&Rate{
|
||||
|
||||
@@ -126,7 +126,6 @@ func GetRateInterval(rpl *utils.TPRatingPlanBinding, dr *utils.DestinationRate)
|
||||
},
|
||||
Weight: rpl.Weight,
|
||||
Rating: &RIRate{
|
||||
Id: dr.Rate.RateId,
|
||||
ConnectFee: dr.Rate.RateSlots[0].ConnectFee,
|
||||
RoundingMethod: dr.Rate.RateSlots[0].RoundingMethod,
|
||||
RoundingDecimals: dr.Rate.RateSlots[0].RoundingDecimals,
|
||||
|
||||
@@ -53,7 +53,6 @@ func (rit *RITiming) Stringify() string {
|
||||
|
||||
// Separate structure used for rating plan size optimization
|
||||
type RIRate struct {
|
||||
Id string // informational role only
|
||||
ConnectFee float64
|
||||
Rates RateGroups // GroupRateInterval (start time): Rate
|
||||
RoundingMethod string //ROUNDING_UP, ROUNDING_DOWN, ROUNDING_MIDDLE
|
||||
|
||||
@@ -89,42 +89,6 @@ func (rs *Responder) RefundIncrements(arg CallDescriptor, reply *float64) (err e
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) DebitCents(arg CallDescriptor, reply *float64) (err error) {
|
||||
if rs.Bal != nil {
|
||||
*reply, err = rs.callMethod(&arg, "Responder.DebitCents")
|
||||
} else {
|
||||
r, e := AccLock.Guard(arg.GetAccountKey(), func() (float64, error) {
|
||||
return arg.DebitCents()
|
||||
})
|
||||
*reply, err = r, e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) DebitSMS(arg CallDescriptor, reply *float64) (err error) {
|
||||
if rs.Bal != nil {
|
||||
*reply, err = rs.callMethod(&arg, "Responder.DebitSMS")
|
||||
} else {
|
||||
r, e := AccLock.Guard(arg.GetAccountKey(), func() (float64, error) {
|
||||
return arg.DebitSMS()
|
||||
})
|
||||
*reply, err = r, e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) DebitSeconds(arg CallDescriptor, reply *float64) (err error) {
|
||||
if rs.Bal != nil {
|
||||
*reply, err = rs.callMethod(&arg, "Responder.DebitSeconds")
|
||||
} else {
|
||||
r, e := AccLock.Guard(arg.GetAccountKey(), func() (float64, error) {
|
||||
return 0, arg.DebitSeconds()
|
||||
})
|
||||
*reply, err = r, e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) GetMaxSessionTime(arg CallDescriptor, reply *float64) (err error) {
|
||||
if rs.Bal != nil {
|
||||
*reply, err = rs.callMethod(&arg, "Responder.GetMaxSessionTime")
|
||||
@@ -138,19 +102,6 @@ func (rs *Responder) GetMaxSessionTime(arg CallDescriptor, reply *float64) (err
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) AddRecievedCallSeconds(arg CallDescriptor, reply *float64) (err error) {
|
||||
if rs.Bal != nil {
|
||||
*reply, err = rs.callMethod(&arg, "Responder.AddRecievedCallSeconds")
|
||||
} else {
|
||||
|
||||
r, e := AccLock.Guard(arg.GetAccountKey(), func() (float64, error) {
|
||||
return 0, arg.AddRecievedCallSeconds()
|
||||
})
|
||||
*reply, err = r, e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Responder) FlushCache(arg CallDescriptor, reply *float64) (err error) {
|
||||
if rs.Bal != nil {
|
||||
*reply, err = rs.callMethod(&arg, "Responder.FlushCache")
|
||||
@@ -200,12 +151,12 @@ func (rs *Responder) GetSMS(arg CallDescriptor, reply *CallCost) (err error) {
|
||||
}
|
||||
|
||||
func (rs *Responder) GetInternet(arg CallDescriptor, reply *CallCost) (err error) {
|
||||
err = rs.getBalance(&arg, TRAFFIC, reply)
|
||||
err = rs.getBalance(&arg, DATA, reply)
|
||||
return err
|
||||
}
|
||||
|
||||
func (rs *Responder) GetInternetTime(arg CallDescriptor, reply *CallCost) (err error) {
|
||||
err = rs.getBalance(&arg, TRAFFIC_TIME, reply)
|
||||
err = rs.getBalance(&arg, DATA_TIME, reply)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -355,8 +306,6 @@ type Connector interface {
|
||||
Debit(CallDescriptor, *CallCost) error
|
||||
MaxDebit(CallDescriptor, *CallCost) error
|
||||
RefundIncrements(CallDescriptor, *float64) error
|
||||
DebitCents(CallDescriptor, *float64) error
|
||||
DebitSeconds(CallDescriptor, *float64) error
|
||||
GetMaxSessionTime(CallDescriptor, *float64) error
|
||||
}
|
||||
|
||||
@@ -375,15 +324,11 @@ func (rcc *RPCClientConnector) Debit(cd CallDescriptor, cc *CallCost) error {
|
||||
func (rcc *RPCClientConnector) MaxDebit(cd CallDescriptor, cc *CallCost) error {
|
||||
return rcc.Client.Call("Responder.MaxDebit", cd, cc)
|
||||
}
|
||||
|
||||
func (rcc *RPCClientConnector) RefundIncrements(cd CallDescriptor, resp *float64) error {
|
||||
return rcc.Client.Call("Responder.RefundIncrements", cd, resp)
|
||||
}
|
||||
func (rcc *RPCClientConnector) DebitCents(cd CallDescriptor, resp *float64) error {
|
||||
return rcc.Client.Call("Responder.DebitCents", cd, resp)
|
||||
}
|
||||
func (rcc *RPCClientConnector) DebitSeconds(cd CallDescriptor, resp *float64) error {
|
||||
return rcc.Client.Call("Responder.DebitSeconds", cd, resp)
|
||||
}
|
||||
|
||||
func (rcc *RPCClientConnector) GetMaxSessionTime(cd CallDescriptor, resp *float64) error {
|
||||
return rcc.Client.Call("Responder.GetMaxSessionTime", cd, resp)
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ func (ms *MapStorage) Flush() error {
|
||||
func (ms *MapStorage) CacheRating(dKeys, rpKeys, rpfKeys, alsKeys []string) error {
|
||||
if dKeys == nil {
|
||||
cache2go.RemPrefixKey(DESTINATION_PREFIX)
|
||||
} else {
|
||||
CleanStalePrefixes(dKeys)
|
||||
}
|
||||
if rpKeys == nil {
|
||||
cache2go.RemPrefixKey(RATING_PLAN_PREFIX)
|
||||
|
||||
@@ -76,6 +76,7 @@ func (rs *RedisStorage) CacheRating(dKeys, rpKeys, rpfKeys, alsKeys []string) (e
|
||||
cache2go.RemPrefixKey(DESTINATION_PREFIX)
|
||||
} else if len(dKeys) != 0 {
|
||||
Logger.Info(fmt.Sprintf("Caching destinations: %v", dKeys))
|
||||
CleanStalePrefixes(dKeys)
|
||||
}
|
||||
for _, key := range dKeys {
|
||||
if _, err = rs.GetDestination(key[len(DESTINATION_PREFIX):]); err != nil {
|
||||
|
||||
@@ -147,7 +147,7 @@ func GetUB() *Account {
|
||||
ub := &Account{
|
||||
Id: "rif",
|
||||
AllowNegative: true,
|
||||
BalanceMap: map[string]BalanceChain{SMS + OUTBOUND: BalanceChain{&Balance{Value: 14, ExpirationDate: zeroTime}}, TRAFFIC + OUTBOUND: BalanceChain{&Balance{Value: 1024, ExpirationDate: zeroTime}}, MINUTES: BalanceChain{&Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}},
|
||||
BalanceMap: map[string]BalanceChain{SMS + OUTBOUND: BalanceChain{&Balance{Value: 14, ExpirationDate: zeroTime}}, DATA + OUTBOUND: BalanceChain{&Balance{Value: 1024, ExpirationDate: zeroTime}}, MINUTES: BalanceChain{&Balance{Weight: 20, DestinationId: "NAT"}, &Balance{Weight: 10, DestinationId: "RET"}}},
|
||||
UnitCounters: []*UnitsCounter{uc, uc},
|
||||
ActionTriggers: ActionTriggerPriotityList{at, at, at},
|
||||
}
|
||||
|
||||
@@ -32,7 +32,17 @@ func IsSliceMember(ss []string, s string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
//Iterates over slice members and returns true of one starts with prefix
|
||||
// Binary string search in slice
|
||||
// returns true if found and the index
|
||||
func GetSliceMemberIndex(ss []string, s string) (bool, int) {
|
||||
sort.Strings(ss)
|
||||
if i := sort.SearchStrings(ss, s); i < len(ss) && ss[i] == s {
|
||||
return true, i
|
||||
}
|
||||
return false, len(ss)
|
||||
}
|
||||
|
||||
//Iterates over slice members and returns true if one starts with prefix
|
||||
func SliceMemberHasPrefix(ss []string, prfx string) bool {
|
||||
for _, mbr := range ss {
|
||||
if strings.HasPrefix(mbr, prfx) {
|
||||
|
||||
Reference in New Issue
Block a user