mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
actions sorters
This commit is contained in:
@@ -27,21 +27,25 @@ import (
|
||||
"log"
|
||||
"runtime"
|
||||
"time"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
raterAddress = flag.String("rateraddr", "127.0.0.1:2000", "Rater server address (localhost:2000)")
|
||||
jsonRpcAddress = flag.String("jsonrpcaddr", "127.0.0.1:2001", "Json RPC server address (localhost:2001)")
|
||||
httpApiAddress = flag.String("httpapiaddr", "127.0.0.1:8000", "Http API server address (localhost:2002)")
|
||||
freeswitchsrv = flag.String("freeswitchsrv", "localhost:8021", "freeswitch address host:port")
|
||||
freeswitchpass = flag.String("freeswitchpass", "ClueCon", "freeswitch address host:port")
|
||||
bal *balancer.Balancer
|
||||
raterAddress = flag.String("rateraddr", "127.0.0.1:2000", "Rater server address (localhost:2000)")
|
||||
jsonRpcAddress = flag.String("jsonrpcaddr", "127.0.0.1:2001", "Json RPC server address (localhost:2001)")
|
||||
httpApiAddress = flag.String("httpapiaddr", "127.0.0.1:8000", "Http API server address (localhost:2002)")
|
||||
freeswitchsrv = flag.String("freeswitchsrv", "localhost:8021", "freeswitch address host:port")
|
||||
freeswitchpass = flag.String("freeswitchpass", "ClueCon", "freeswitch address host:port")
|
||||
bal *balancer.Balancer
|
||||
balancerRWMutex sync.RWMutex
|
||||
)
|
||||
|
||||
/*
|
||||
The function that gets the information from the raters using balancer.
|
||||
*/
|
||||
func GetCallCost(key *timespans.CallDescriptor, method string) (reply *timespans.CallCost) {
|
||||
balancerRWMutex.RLock()
|
||||
defer balancerRWMutex
|
||||
err := errors.New("") //not nil value
|
||||
for err != nil {
|
||||
client := bal.Balance()
|
||||
|
||||
@@ -40,25 +40,8 @@ var (
|
||||
s = scheduler{}
|
||||
)
|
||||
|
||||
/*
|
||||
Structure to store action timings according to next activation time.
|
||||
*/
|
||||
type actiontimingqueue []*timespans.ActionTiming
|
||||
|
||||
func (atq actiontimingqueue) Len() int {
|
||||
return len(atq)
|
||||
}
|
||||
|
||||
func (atq actiontimingqueue) Swap(i, j int) {
|
||||
atq[i], atq[j] = atq[j], atq[i]
|
||||
}
|
||||
|
||||
func (atq actiontimingqueue) Less(j, i int) bool {
|
||||
return atq[j].GetNextStartTime().Before(atq[i].GetNextStartTime())
|
||||
}
|
||||
|
||||
type scheduler struct {
|
||||
queue actiontimingqueue
|
||||
queue timespans.ActionTimingPriotityList
|
||||
}
|
||||
|
||||
func (s scheduler) loop() {
|
||||
@@ -110,7 +93,7 @@ func loadActionTimings() {
|
||||
log.Fatalf("Cannot get action timings:", err)
|
||||
}
|
||||
// recreate the queue
|
||||
s.queue = actiontimingqueue{}
|
||||
s.queue = timespans.ActionTimingPriotityList{}
|
||||
for _, at := range actionTimings {
|
||||
if at.IsOneTimeRun() {
|
||||
log.Print("Executing: ", at)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Tag,ActionsTag,TimingTag
|
||||
STANDARD_ABO,SOME,WEEKLY_SAME_TIME
|
||||
STANDARD_ABO,SOME,WEEKLY_SAME_TIME
|
||||
STANDARD_ABO,SOME,WEEKLY_SAME_TIME
|
||||
STANDARD_ABO,SOME,ONE_TIME_RUN
|
||||
STANDARD_ABO,SOME,FIRST_DAY_OF_MONTH
|
||||
MORE_MINUTES,MINI,ONE_TIME_RUN
|
||||
Tag,ActionsTag,TimingTag, Weight
|
||||
STANDARD_ABO,SOME,WEEKLY_SAME_TIME,10
|
||||
STANDARD_ABO,SOME,WEEKLY_SAME_TIME,10
|
||||
STANDARD_ABO,SOME,WEEKLY_SAME_TIME,10
|
||||
STANDARD_ABO,SOME,ONE_TIME_RUN,10
|
||||
STANDARD_ABO,SOME,FIRST_DAY_OF_MONTH,10
|
||||
MORE_MINUTES,MINI,ONE_TIME_RUN,10
|
||||
|
@@ -1,5 +1,5 @@
|
||||
Tag,BalanceTag,ThresholdValue,DestinationTag,ActionsTag
|
||||
STANDARD_TRIGGER,MONETARY,30,*all,SOME_1
|
||||
STANDARD_TRIGGER,SMS,30,*all,SOME_2
|
||||
STANDARD_TRIGGER,MINUTES,10,GERMANY_O2,SOME_1
|
||||
STANDARD_TRIGGER,MINUTES,200,GERMANY,SOME_2
|
||||
Tag,BalanceTag,ThresholdValue,DestinationTag,ActionsTag,Weight
|
||||
STANDARD_TRIGGER,MONETARY,30,*all,SOME_1,10
|
||||
STANDARD_TRIGGER,SMS,30,*all,SOME_2,10
|
||||
STANDARD_TRIGGER,MINUTES,10,GERMANY_O2,SOME_1,10
|
||||
STANDARD_TRIGGER,MINUTES,200,GERMANY,SOME_2,10
|
||||
|
@@ -1,9 +1,9 @@
|
||||
Tag,Action,BalanceTag,Units,DestinationTag,PriceType,PriceValue,Weight
|
||||
SOME,TOPUP_RESET,MONETARY,10,*all,,,
|
||||
SOME,TOPUP_RESET,SMS,100,*all,,,
|
||||
SOME,TOPUP_RESET,INTERNET,1000,*all,,,
|
||||
SOME,POSTPAID_RESET,MONETARY,10,*all,,,
|
||||
SOME,DEBIT,MONETARY,5,*all,,,
|
||||
SOME_1,DEBIT,MINUTES,10,GERMANY_O2,PERCENT,25,10
|
||||
SOME_2,TOPUP_RESET,MINUTES,1000,GERMANY,ABSOLUTE,0.2,10
|
||||
MINI,TOPUP,MINUTES,100,NAT,ABSOLUTE,0,10
|
||||
Tag,Action,BalanceTag,Units,DestinationTag,PriceType,PriceValue,MinutesWeight,Weight
|
||||
SOME,TOPUP_RESET,MONETARY,10,*all,,,,10
|
||||
SOME,TOPUP_RESET,SMS,100,*all,,,,10
|
||||
SOME,TOPUP_RESET,INTERNET,1000,*all,,,,10
|
||||
SOME,POSTPAID_RESET,MONETARY,10,*all,,,,10
|
||||
SOME,DEBIT,MONETARY,5,*all,,,,10
|
||||
SOME_1,DEBIT,MINUTES,10,GERMANY_O2,PERCENT,25,10,10
|
||||
SOME_2,TOPUP_RESET,MINUTES,1000,GERMANY,ABSOLUTE,0.2,10,10
|
||||
MINI,TOPUP,MINUTES,100,NAT,ABSOLUTE,0,10,10
|
||||
|
127
timespans/action.go
Normal file
127
timespans/action.go
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2012 Radu Ioan Fericean
|
||||
|
||||
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 timespans
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sort"
|
||||
)
|
||||
|
||||
/*
|
||||
Structure to be filled for each tariff plan with the bonus value for received calls minutes.
|
||||
*/
|
||||
type Action struct {
|
||||
ActionType string
|
||||
BalanceId string
|
||||
Units float64
|
||||
Weight float64
|
||||
MinuteBucket *MinuteBucket
|
||||
}
|
||||
|
||||
type actionTypeFunc func(*UserBalance, *Action) error
|
||||
|
||||
var (
|
||||
actionTypeFuncMap = map[string]actionTypeFunc{
|
||||
"LOG": logAction,
|
||||
"RESET_TRIGGERS": resetTriggersAction,
|
||||
"SET_POSTPAID": setPostpaidAction,
|
||||
"RESET_POSTPAID": resetPostpaidAction,
|
||||
"SET_PREPAID": setPrepaidAction,
|
||||
"RESET_PREPAID": resetPrepaidAction,
|
||||
"TOPUP_RESET": topupResetAction,
|
||||
"TOPUP": topupAction,
|
||||
"DEBIT": debitAction,
|
||||
"RESET_COUNTERS": resetCountersAction,
|
||||
}
|
||||
)
|
||||
|
||||
func logAction(ub *UserBalance, a *Action) (err error) {
|
||||
log.Printf("%v %v %v", a.BalanceId, a.Units, a.MinuteBucket)
|
||||
return
|
||||
}
|
||||
|
||||
func resetTriggersAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.resetActionTriggers()
|
||||
return
|
||||
}
|
||||
|
||||
func setPostpaidAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.Type = UB_TYPE_POSTPAID
|
||||
return
|
||||
}
|
||||
|
||||
func resetPostpaidAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.Type = UB_TYPE_POSTPAID
|
||||
return
|
||||
}
|
||||
|
||||
func setPrepaidAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.Type = UB_TYPE_PREPAID
|
||||
return
|
||||
}
|
||||
|
||||
func resetPrepaidAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.Type = UB_TYPE_PREPAID
|
||||
return
|
||||
}
|
||||
|
||||
func topupResetAction(ub *UserBalance, a *Action) (err error) {
|
||||
if ub.BalanceMap == nil {
|
||||
ub.BalanceMap = make(map[string]float64)
|
||||
}
|
||||
ub.BalanceMap[a.BalanceId] = a.Units
|
||||
return
|
||||
}
|
||||
|
||||
func topupAction(ub *UserBalance, a *Action) (err error) {
|
||||
if ub.BalanceMap == nil {
|
||||
ub.BalanceMap = make(map[string]float64)
|
||||
}
|
||||
ub.BalanceMap[a.BalanceId] += a.Units
|
||||
ub.addMinuteBucket(a.MinuteBucket)
|
||||
return
|
||||
}
|
||||
|
||||
func debitAction(ub *UserBalance, a *Action) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func resetCountersAction(ub *UserBalance, a *Action) (err error) {
|
||||
//ub.UnitsCounters
|
||||
return
|
||||
}
|
||||
|
||||
// Structure to store actions according to weight
|
||||
type ActionPriotityList []*Action
|
||||
|
||||
func (apl ActionPriotityList) Len() int {
|
||||
return len(apl)
|
||||
}
|
||||
|
||||
func (apl ActionPriotityList) Swap(i, j int) {
|
||||
apl[i], apl[j] = apl[j], apl[i]
|
||||
}
|
||||
|
||||
func (apl ActionPriotityList) Less(i, j int) bool {
|
||||
return apl[i].Weight < apl[j].Weight
|
||||
}
|
||||
|
||||
func (apl ActionPriotityList) Sort() {
|
||||
sort.Sort(apl)
|
||||
}
|
||||
@@ -29,183 +29,13 @@ const (
|
||||
FORMAT = "2006-1-2 15:04:05 MST"
|
||||
)
|
||||
|
||||
// Amount of a trafic of a certain type
|
||||
type UnitsCounter struct {
|
||||
Direction string
|
||||
BalanceId string
|
||||
Units float64
|
||||
Weight float64
|
||||
MinuteBuckets []*MinuteBucket
|
||||
}
|
||||
|
||||
// Structure to store actions according to weight
|
||||
type countersorter []*UnitsCounter
|
||||
|
||||
func (s countersorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s countersorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s countersorter) Less(i, j int) bool {
|
||||
return s[i].Weight < s[j].Weight
|
||||
}
|
||||
|
||||
/*
|
||||
Structure to be filled for each tariff plan with the bonus value for received calls minutes.
|
||||
*/
|
||||
type Action struct {
|
||||
ActionType string
|
||||
BalanceId string
|
||||
Units float64
|
||||
MinuteBucket *MinuteBucket
|
||||
}
|
||||
|
||||
type actionTypeFunc func(*UserBalance, *Action) error
|
||||
|
||||
var (
|
||||
actionTypeFuncMap = map[string]actionTypeFunc{
|
||||
"LOG": logAction,
|
||||
"RESET_TRIGGERS": resetTriggersAction,
|
||||
"SET_POSTPAID": setPostpaidAction,
|
||||
"RESET_POSTPAID": resetPostpaidAction,
|
||||
"SET_PREPAID": setPrepaidAction,
|
||||
"RESET_PREPAID": resetPrepaidAction,
|
||||
"TOPUP_RESET": topupResetAction,
|
||||
"TOPUP": topupAction,
|
||||
"DEBIT": debitAction,
|
||||
"RESET_COUNTERS": resetCountersAction,
|
||||
}
|
||||
)
|
||||
|
||||
func logAction(ub *UserBalance, a *Action) (err error) {
|
||||
log.Printf("%v %v %v", a.BalanceId, a.Units, a.MinuteBucket)
|
||||
return
|
||||
}
|
||||
|
||||
func resetTriggersAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.resetActionTriggers()
|
||||
return
|
||||
}
|
||||
|
||||
func setPostpaidAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.Type = UB_TYPE_POSTPAID
|
||||
return
|
||||
}
|
||||
|
||||
func resetPostpaidAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.Type = UB_TYPE_POSTPAID
|
||||
return
|
||||
}
|
||||
|
||||
func setPrepaidAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.Type = UB_TYPE_PREPAID
|
||||
return
|
||||
}
|
||||
|
||||
func resetPrepaidAction(ub *UserBalance, a *Action) (err error) {
|
||||
ub.Type = UB_TYPE_PREPAID
|
||||
return
|
||||
}
|
||||
|
||||
func topupResetAction(ub *UserBalance, a *Action) (err error) {
|
||||
if ub.BalanceMap == nil {
|
||||
ub.BalanceMap = make(map[string]float64)
|
||||
}
|
||||
ub.BalanceMap[a.BalanceId] = a.Units
|
||||
return storageGetter.SetUserBalance(ub)
|
||||
}
|
||||
|
||||
func topupAction(ub *UserBalance, a *Action) (err error) {
|
||||
if ub.BalanceMap == nil {
|
||||
ub.BalanceMap = make(map[string]float64)
|
||||
}
|
||||
ub.BalanceMap[a.BalanceId] += a.Units
|
||||
ub.addMinuteBucket(a.MinuteBucket)
|
||||
return storageGetter.SetUserBalance(ub)
|
||||
}
|
||||
|
||||
func debitAction(ub *UserBalance, a *Action) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func resetCountersAction(ub *UserBalance, a *Action) (err error) {
|
||||
//ub.UnitsCounters
|
||||
return
|
||||
}
|
||||
|
||||
type ActionTrigger struct {
|
||||
BalanceId string
|
||||
ThresholdValue float64
|
||||
DestinationId string
|
||||
Priority float64
|
||||
ActionsId string
|
||||
executed bool
|
||||
}
|
||||
|
||||
func (at *ActionTrigger) Execute(ub *UserBalance) (err error) {
|
||||
aac, err := storageGetter.GetActions(at.ActionsId)
|
||||
if err != nil {
|
||||
log.Print("Failed to get actions: ", err)
|
||||
return
|
||||
}
|
||||
for _, a := range aac {
|
||||
actionFunction, exists := actionTypeFuncMap[a.ActionType]
|
||||
if !exists {
|
||||
log.Printf("Function type %v not available, aborting execution!", a.ActionType)
|
||||
return
|
||||
}
|
||||
err = actionFunction(ub, a)
|
||||
}
|
||||
at.executed = true
|
||||
return
|
||||
}
|
||||
|
||||
// Structure to store actions according to weight
|
||||
type ActionTriggerPriotityList []*ActionTrigger
|
||||
|
||||
func (atpl ActionTriggerPriotityList) Len() int {
|
||||
return len(atpl)
|
||||
}
|
||||
|
||||
func (atpl ActionTriggerPriotityList) Swap(i, j int) {
|
||||
atpl[i], atpl[j] = atpl[j], atpl[i]
|
||||
}
|
||||
|
||||
func (atpl ActionTriggerPriotityList) Less(i, j int) bool {
|
||||
return atpl[i].Priority < atpl[j].Priority
|
||||
}
|
||||
|
||||
func (atpl ActionTriggerPriotityList) Sort() {
|
||||
sort.Sort(atpl)
|
||||
}
|
||||
|
||||
type ActionTiming struct {
|
||||
Tag string // informative purpos only
|
||||
UserBalanceIds []string
|
||||
Timing *Interval
|
||||
Weight float64
|
||||
ActionsId string
|
||||
actions []*Action
|
||||
}
|
||||
|
||||
func (at *ActionTiming) getActions() (as []*Action, err error) {
|
||||
if at.actions == nil {
|
||||
at.actions, err = storageGetter.GetActions(at.ActionsId)
|
||||
}
|
||||
return at.actions, err
|
||||
}
|
||||
|
||||
func (at *ActionTiming) getUserBalances() (ubs []*UserBalance) {
|
||||
for _, ubId := range at.UserBalanceIds {
|
||||
ub, err := storageGetter.GetUserBalance(ubId)
|
||||
if err != nil {
|
||||
log.Printf("Could not get user balances for therse id: %v. Skipping!", ubId)
|
||||
}
|
||||
ubs = append(ubs, ub)
|
||||
}
|
||||
return
|
||||
actions ActionPriotityList
|
||||
}
|
||||
|
||||
func (at *ActionTiming) GetNextStartTime() (t time.Time) {
|
||||
@@ -298,7 +128,28 @@ MONTHS:
|
||||
return
|
||||
}
|
||||
|
||||
func (at *ActionTiming) getActions() (as []*Action, err error) {
|
||||
if at.actions == nil {
|
||||
at.actions, err = storageGetter.GetActions(at.ActionsId)
|
||||
}
|
||||
at.actions.Sort()
|
||||
return at.actions, err
|
||||
}
|
||||
|
||||
func (at *ActionTiming) getUserBalances() (ubs []*UserBalance) {
|
||||
for _, ubId := range at.UserBalanceIds {
|
||||
ub, err := storageGetter.GetUserBalance(ubId)
|
||||
if err != nil {
|
||||
log.Printf("Could not get user balances for therse id: %v. Skipping!", ubId)
|
||||
}
|
||||
ubs = append(ubs, ub)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (at *ActionTiming) Execute() (err error) {
|
||||
userBalancesRWMutex.Lock()
|
||||
defer userBalancesRWMutex.Unlock()
|
||||
aac, err := at.getActions()
|
||||
if err != nil {
|
||||
log.Print("Failed to get actions: ", err)
|
||||
@@ -312,6 +163,7 @@ func (at *ActionTiming) Execute() (err error) {
|
||||
}
|
||||
for _, ub := range at.getUserBalances() {
|
||||
err = actionFunction(ub, a)
|
||||
storageGetter.SetUserBalance(ub)
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -324,3 +176,22 @@ func (at *ActionTiming) IsOneTimeRun() bool {
|
||||
}
|
||||
return len(i.Months) == 0 && len(i.MonthDays) == 0 && len(i.WeekDays) == 0
|
||||
}
|
||||
|
||||
// Structure to store actions according to weight
|
||||
type ActionTimingPriotityList []*ActionTiming
|
||||
|
||||
func (atpl ActionTimingPriotityList) Len() int {
|
||||
return len(atpl)
|
||||
}
|
||||
|
||||
func (atpl ActionTimingPriotityList) Swap(i, j int) {
|
||||
atpl[i], atpl[j] = atpl[j], atpl[i]
|
||||
}
|
||||
|
||||
func (atpl ActionTimingPriotityList) Less(i, j int) bool {
|
||||
return atpl[i].GetNextStartTime().Before(atpl[j].GetNextStartTime()) || atpl[i].Weight < atpl[j].Weight
|
||||
}
|
||||
|
||||
func (atpl ActionTimingPriotityList) Sort() {
|
||||
sort.Sort(atpl)
|
||||
}
|
||||
75
timespans/action_trigger.go
Normal file
75
timespans/action_trigger.go
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2012 Radu Ioan Fericean
|
||||
|
||||
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 timespans
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type ActionTrigger struct {
|
||||
BalanceId string
|
||||
ThresholdValue float64
|
||||
DestinationId string
|
||||
Weight float64
|
||||
ActionsId string
|
||||
executed bool
|
||||
}
|
||||
|
||||
func (at *ActionTrigger) Execute(ub *UserBalance) (err error) {
|
||||
userBalancesRWMutex.Lock()
|
||||
defer userBalancesRWMutex.Unlock()
|
||||
var aac ActionPriotityList
|
||||
aac, err = storageGetter.GetActions(at.ActionsId)
|
||||
aac.Sort()
|
||||
if err != nil {
|
||||
log.Print("Failed to get actions: ", err)
|
||||
return
|
||||
}
|
||||
for _, a := range aac {
|
||||
actionFunction, exists := actionTypeFuncMap[a.ActionType]
|
||||
if !exists {
|
||||
log.Printf("Function type %v not available, aborting execution!", a.ActionType)
|
||||
return
|
||||
}
|
||||
err = actionFunction(ub, a)
|
||||
}
|
||||
at.executed = true
|
||||
storageGetter.SetUserBalance(ub)
|
||||
return
|
||||
}
|
||||
|
||||
// Structure to store actions according to weight
|
||||
type ActionTriggerPriotityList []*ActionTrigger
|
||||
|
||||
func (atpl ActionTriggerPriotityList) Len() int {
|
||||
return len(atpl)
|
||||
}
|
||||
|
||||
func (atpl ActionTriggerPriotityList) Swap(i, j int) {
|
||||
atpl[i], atpl[j] = atpl[j], atpl[i]
|
||||
}
|
||||
|
||||
func (atpl ActionTriggerPriotityList) Less(i, j int) bool {
|
||||
return atpl[i].Weight < atpl[j].Weight
|
||||
}
|
||||
|
||||
func (atpl ActionTriggerPriotityList) Sort() {
|
||||
sort.Sort(atpl)
|
||||
}
|
||||
@@ -232,9 +232,9 @@ func TestActionTimingLogFunction(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestActionTriggerPriotityList(t *testing.T) {
|
||||
at1 := &ActionTrigger{Priority: 10}
|
||||
at2 := &ActionTrigger{Priority: 20}
|
||||
at3 := &ActionTrigger{Priority: 30}
|
||||
at1 := &ActionTrigger{Weight: 10}
|
||||
at2 := &ActionTrigger{Weight: 20}
|
||||
at3 := &ActionTrigger{Weight: 30}
|
||||
var atpl ActionTriggerPriotityList
|
||||
atpl = append(atpl, at2, at1, at3)
|
||||
atpl.Sort()
|
||||
|
||||
@@ -175,6 +175,8 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
|
||||
Splits the received timespan into sub time spans according to the activation periods intervals.
|
||||
*/
|
||||
func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeSpan) {
|
||||
userBalancesRWMutex.RLock()
|
||||
defer userBalancesRWMutex.RUnlock()
|
||||
timespans = append(timespans, firstSpan)
|
||||
// split on (free) minute buckets
|
||||
if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
|
||||
@@ -289,6 +291,8 @@ and will decrease it by 10% for nine times. So if the user has little credit it
|
||||
If the user has no credit then it will return 0.
|
||||
*/
|
||||
func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) {
|
||||
userBalancesRWMutex.RLock()
|
||||
defer userBalancesRWMutex.RUnlock()
|
||||
_, err = cd.SearchStorageForPrefix()
|
||||
now := time.Now()
|
||||
availableCredit, availableSeconds := 0.0, 0.0
|
||||
@@ -331,6 +335,8 @@ func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) {
|
||||
// Interface method used to add/substract an amount of cents or bonus seconds (as returned by GetCost method)
|
||||
// from user's money balance.
|
||||
func (cd *CallDescriptor) Debit() (cc *CallCost, err error) {
|
||||
userBalancesRWMutex.Lock()
|
||||
defer userBalancesRWMutex.Unlock()
|
||||
cc, err = cd.GetCost()
|
||||
if err != nil {
|
||||
log.Printf("error getting cost %v", err)
|
||||
@@ -353,6 +359,8 @@ Interface method used to add/substract an amount of cents from user's money bala
|
||||
The amount filed has to be filled in call descriptor.
|
||||
*/
|
||||
func (cd *CallDescriptor) DebitCents() (left float64, err error) {
|
||||
userBalancesRWMutex.Lock()
|
||||
defer userBalancesRWMutex.Unlock()
|
||||
if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
|
||||
return userBalance.debitMoneyBalance(cd.Amount), nil
|
||||
}
|
||||
@@ -364,6 +372,8 @@ Interface method used to add/substract an amount of units from user's sms balanc
|
||||
The amount filed has to be filled in call descriptor.
|
||||
*/
|
||||
func (cd *CallDescriptor) DebitSMS() (left float64, err error) {
|
||||
userBalancesRWMutex.Lock()
|
||||
defer userBalancesRWMutex.Unlock()
|
||||
if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
|
||||
return userBalance.debitSMSBuget(cd.Amount)
|
||||
}
|
||||
@@ -375,6 +385,8 @@ Interface method used to add/substract an amount of seconds from user's minutes
|
||||
The amount filed has to be filled in call descriptor.
|
||||
*/
|
||||
func (cd *CallDescriptor) DebitSeconds() (err error) {
|
||||
userBalancesRWMutex.Lock()
|
||||
defer userBalancesRWMutex.Unlock()
|
||||
if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
|
||||
return userBalance.debitMinutesBalance(cd.Amount, cd.Destination)
|
||||
}
|
||||
@@ -388,6 +400,8 @@ specified in the tariff plan is applied.
|
||||
The amount filed has to be filled in call descriptor.
|
||||
*/
|
||||
// func (cd *CallDescriptor) AddRecievedCallSeconds() (err error) {
|
||||
// userBalancesRWMutex.Lock()
|
||||
// defer userBalancesRWMutex.Unlock()
|
||||
// if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
|
||||
// return userBalance.addReceivedCallSeconds(INBOUND, cd.TOR, cd.Destination, cd.Amount)
|
||||
// }
|
||||
@@ -398,6 +412,8 @@ The amount filed has to be filled in call descriptor.
|
||||
Resets user balances value to the amounts specified in the tariff plan.
|
||||
*/
|
||||
/*func (cd *CallDescriptor) ResetUserBalance() (err error) {
|
||||
userBalancesRWMutex.Lock()
|
||||
defer userBalancesRWMutex.Unlock()
|
||||
if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
|
||||
return userBalance.resetUserBalance()
|
||||
}
|
||||
|
||||
@@ -199,23 +199,6 @@ func TestMaxSessionTimeNoCredit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
/*func TestGetCostWithVolumeDiscount(t *testing.T) {
|
||||
storageGetter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer storageGetter.Close()
|
||||
vd1 := &VolumeDiscount{100, 10}
|
||||
vd2 := &VolumeDiscount{500, 20}
|
||||
seara := &TariffPlan{Id: "seara", SmsCredit: 100, VolumeDiscountThresholds: []*VolumeDiscount{vd1, vd2}}
|
||||
rifsBalance := &UserBalance{Id: "rif", Credit: 21, tariffPlan: seara, ResetDayOfTheMonth: 10, VolumeDiscountSeconds: 105}
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0723", TimeStart: t1, TimeEnd: t2, userBalance: rifsBalance}
|
||||
callCost, err := cd.GetCost()
|
||||
if callCost.Cost != 54.0 || err != nil {
|
||||
t.Errorf("Expected %v was %v", 54.0, callCost)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func TestApAddAPIfNotPresent(t *testing.T) {
|
||||
ap1 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)}
|
||||
ap2 := &ActivationPeriod{ActivationTime: time.Date(2012, time.July, 2, 14, 24, 30, 0, time.UTC)}
|
||||
|
||||
@@ -19,7 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package timespans
|
||||
|
||||
import (
|
||||
// "log"
|
||||
// "log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -40,7 +41,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
storageGetter StorageGetter
|
||||
storageGetter StorageGetter
|
||||
userBalancesRWMutex sync.RWMutex
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -263,3 +265,26 @@ Resets the user balance items to their tariff plan values.
|
||||
return
|
||||
}
|
||||
*/
|
||||
// Amount of a trafic of a certain type
|
||||
type UnitsCounter struct {
|
||||
Direction string
|
||||
BalanceId string
|
||||
Units float64
|
||||
Weight float64
|
||||
MinuteBuckets []*MinuteBucket
|
||||
}
|
||||
|
||||
// Structure to store actions according to weight
|
||||
type countersorter []*UnitsCounter
|
||||
|
||||
func (s countersorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s countersorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s countersorter) Less(i, j int) bool {
|
||||
return s[i].Weight < s[j].Weight
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user