From 9d228d80bfa8cd49a3b8bd4c1320445246c3ed5e Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Mon, 14 Dec 2015 22:30:36 +0200 Subject: [PATCH] restructured action plan --- engine/action_plan.go | 118 +++++++++++++----------------------- engine/action_trigger.go | 41 ------------- engine/actions_test.go | 109 +++++++++++++++++---------------- engine/calldesc_test.go | 110 +++++++++++++++++++-------------- engine/loader_csv_test.go | 41 +++++++++---- engine/storage_interface.go | 8 +-- engine/storage_map.go | 18 +++--- engine/storage_mongo.go | 20 +++--- engine/storage_mongo_tp.go | 4 +- engine/storage_redis.go | 16 ++--- engine/storage_sql.go | 2 +- engine/tp_reader.go | 72 +++++++++++----------- 12 files changed, 262 insertions(+), 297 deletions(-) diff --git a/engine/action_plan.go b/engine/action_plan.go index 6bdea2c4c..231c9568e 100644 --- a/engine/action_plan.go +++ b/engine/action_plan.go @@ -21,7 +21,6 @@ package engine import ( "fmt" "sort" - "strconv" "time" "github.com/cgrates/cgrates/utils" @@ -32,20 +31,31 @@ const ( FORMAT = "2006-1-2 15:04:05 MST" ) -type ActionPlan struct { - Uuid string // uniquely identify the timing - Id string // informative purpose only - AccountIds []string +type ActionTiming struct { + Uuid string Timing *RateInterval - Weight float64 ActionsId string + Weight float64 actions Actions + accountIDs map[string]struct{} stCache time.Time // cached time of the next start } -type ActionPlans []*ActionPlan +type ActionPlan struct { + Uuid string // uniquely identify the timing + Id string // informative purpose only + AccountIDs map[string]struct{} + ActionTimings []*ActionTiming +} -func (at *ActionPlan) GetNextStartTime(now time.Time) (t time.Time) { +func (apl *ActionPlan) RemoveAccountID(accID string) (found bool) { + if _, found = apl.AccountIDs[accID]; found { + delete(apl.AccountIDs, accID) + } + return +} + +func (at *ActionTiming) GetNextStartTime(now time.Time) (t time.Time) { if !at.stCache.IsZero() { return at.stCache } @@ -68,7 +78,7 @@ func (at *ActionPlan) GetNextStartTime(now time.Time) (t time.Time) { } // To be deleted after the above solution proves reliable -func (at *ActionPlan) GetNextStartTimeOld(now time.Time) (t time.Time) { +func (at *ActionTiming) GetNextStartTimeOld(now time.Time) (t time.Time) { if !at.stCache.IsZero() { return at.stCache } @@ -218,15 +228,15 @@ YEARS: return } -func (at *ActionPlan) ResetStartTimeCache() { +func (at *ActionTiming) ResetStartTimeCache() { at.stCache = time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) } -func (at *ActionPlan) SetActions(as Actions) { +func (at *ActionTiming) SetActions(as Actions) { at.actions = as } -func (at *ActionPlan) getActions() (as []*Action, err error) { +func (at *ActionTiming) getActions() (as []*Action, err error) { if at.actions == nil { at.actions, err = ratingStorage.GetActions(at.ActionsId, false) } @@ -234,8 +244,8 @@ func (at *ActionPlan) getActions() (as []*Action, err error) { return at.actions, err } -func (at *ActionPlan) Execute() (err error) { - if len(at.AccountIds) == 0 { // nothing to do if no accounts set +func (at *ActionTiming) Execute() (err error) { + if len(at.accountIDs) == 0 { // nothing to do if no accounts set return } at.ResetStartTimeCache() @@ -244,8 +254,8 @@ func (at *ActionPlan) Execute() (err error) { utils.Logger.Err(fmt.Sprintf("Failed to get actions for %s: %s", at.ActionsId, err)) return } - _, err = Guardian.Guard(func() (interface{}, error) { - for _, accId := range at.AccountIds { + for accId, _ := range at.accountIDs { + _, err = Guardian.Guard(func() (interface{}, error) { ub, err := accountingStorage.GetAccount(accId) if err != nil { utils.Logger.Warning(fmt.Sprintf("Could not get user balances for this id: %s. Skipping!", accId)) @@ -261,45 +271,7 @@ func (at *ActionPlan) Execute() (err error) { if expDate, parseErr := utils.ParseDate(a.ExpirationString); (a.Balance == nil || a.Balance.ExpirationDate.IsZero()) && parseErr == nil && !expDate.IsZero() { a.Balance.ExpirationDate = expDate } - // handle remove action - if a.ActionType == REMOVE_ACCOUNT { - if err := accountingStorage.RemoveAccount(accId); err != nil { - utils.Logger.Err(fmt.Sprintf("Could not remove account Id: %s: %v", accId, err)) - transactionFailed = true - break - } - // clean the account id from all action plans - allATs, err := ratingStorage.GetAllActionPlans() - if err != nil && err != utils.ErrNotFound { - utils.Logger.Err(fmt.Sprintf("Could not get action plans: %s: %v", accId, err)) - transactionFailed = true - break - } - for key, ats := range allATs { - changed := false - for _, at := range ats { - for i := 0; i < len(at.AccountIds); i++ { - if at.AccountIds[i] == accId { - // delete without preserving order - at.AccountIds[i] = at.AccountIds[len(at.AccountIds)-1] - at.AccountIds = at.AccountIds[:len(at.AccountIds)-1] - i-- - changed = true - } - } - } - if changed { - // save action plan - ratingStorage.SetActionPlans(key, ats) - // cache - ratingStorage.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PLAN_PREFIX: []string{utils.ACTION_PLAN_PREFIX + key}}) - } - } - toBeSaved = false - continue // do not go to getActionFunc - // TODO: maybe we should break here as the account is gone - // will leave continue for now as the next action can create another acount - } + actionFunction, exists := getActionFunc(a.ActionType) if !exists { // do not allow the action plan to be rescheduled @@ -318,18 +290,18 @@ func (at *ActionPlan) Execute() (err error) { if !transactionFailed && toBeSaved { accountingStorage.SetAccount(ub) } - } - return 0, nil - }, 0, at.AccountIds...) + return 0, nil + }, 0, accId) + } if err != nil { utils.Logger.Warning(fmt.Sprintf("Error executing action plan: %v", err)) return err } - storageLogger.LogActionPlan(utils.SCHED_SOURCE, at, aac) + storageLogger.LogActionTiming(utils.SCHED_SOURCE, at, aac) return } -func (at *ActionPlan) IsASAP() bool { +func (at *ActionTiming) IsASAP() bool { if at.Timing == nil { return false } @@ -337,17 +309,17 @@ func (at *ActionPlan) IsASAP() bool { } // Structure to store actions according to weight -type ActionPlanPriotityList []*ActionPlan +type ActionTimingPriorityList []*ActionTiming -func (atpl ActionPlanPriotityList) Len() int { +func (atpl ActionTimingPriorityList) Len() int { return len(atpl) } -func (atpl ActionPlanPriotityList) Swap(i, j int) { +func (atpl ActionTimingPriorityList) Swap(i, j int) { atpl[i], atpl[j] = atpl[j], atpl[i] } -func (atpl ActionPlanPriotityList) Less(i, j int) bool { +func (atpl ActionTimingPriorityList) Less(i, j int) bool { if atpl[i].GetNextStartTime(time.Now()).Equal(atpl[j].GetNextStartTime(time.Now())) { // higher weights earlyer in the list return atpl[i].Weight > atpl[j].Weight @@ -355,20 +327,16 @@ func (atpl ActionPlanPriotityList) Less(i, j int) bool { return atpl[i].GetNextStartTime(time.Now()).Before(atpl[j].GetNextStartTime(time.Now())) } -func (atpl ActionPlanPriotityList) Sort() { +func (atpl ActionTimingPriorityList) Sort() { sort.Sort(atpl) } -func (at *ActionPlan) String_DISABLED() string { - return at.Id + " " + at.GetNextStartTime(time.Now()).String() + ",w: " + strconv.FormatFloat(at.Weight, 'f', -1, 64) -} - // Helper to remove ActionPlan members based on specific filters, empty data means no always match -func RemActionPlan(ats ActionPlans, actionTimingId, accountId string) ActionPlans { - for idx, at := range ats { - if len(actionTimingId) != 0 && at.Uuid != actionTimingId { // No Match for ActionPlanId, no need to move further - continue - } +/*func RemActionPlan(apl ActionPlan, actionTimingId, accountId string) ActionPlan { + if len(actionTimingId) != 0 && apl.Uuid != actionTimingId { // No Match for ActionPlanId, no need to move further + continue + } + for idx, ats := range apl.ActionTimings { if len(accountId) == 0 { // No account defined, considered match for complete removal if len(ats) == 1 { // Removing last item, by init empty return make([]*ActionPlan, 0) @@ -392,4 +360,4 @@ func RemActionPlan(ats ActionPlans, actionTimingId, accountId string) ActionPlan } } return ats -} +}*/ diff --git a/engine/action_trigger.go b/engine/action_trigger.go index e6de7d1e3..c7bec094b 100644 --- a/engine/action_trigger.go +++ b/engine/action_trigger.go @@ -79,47 +79,6 @@ func (at *ActionTrigger) Execute(ub *Account, sq *StatsQueueTriggered) (err erro a.Balance = &Balance{} } a.Balance.ExpirationDate, _ = utils.ParseDate(a.ExpirationString) - // handle remove action - if a.ActionType == REMOVE_ACCOUNT { - accId := ub.Id - if err := accountingStorage.RemoveAccount(accId); err != nil { - utils.Logger.Err(fmt.Sprintf("Could not remove account Id: %s: %v", accId, err)) - transactionFailed = true - break - } - // clean the account id from all action plans - allATs, err := ratingStorage.GetAllActionPlans() - if err != nil && err != utils.ErrNotFound { - utils.Logger.Err(fmt.Sprintf("Could not get action plans: %s: %v", accId, err)) - transactionFailed = true - break - } - for key, ats := range allATs { - changed := false - for _, at := range ats { - for i := 0; i < len(at.AccountIds); i++ { - if at.AccountIds[i] == accId { - // delete without preserving order - at.AccountIds[i] = at.AccountIds[len(at.AccountIds)-1] - at.AccountIds = at.AccountIds[:len(at.AccountIds)-1] - i -= 1 - changed = true - } - } - } - if changed { - // save action plan - ratingStorage.SetActionPlans(key, ats) - // cache - ratingStorage.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PLAN_PREFIX: []string{utils.ACTION_PLAN_PREFIX + key}}) - } - } - toBeSaved = false - continue // do not go to getActionFunc - // TODO: maybe we should break here as the account is gone - // will leave continue for now as the next action can create another acount - } - actionFunction, exists := getActionFunc(a.ActionType) if !exists { utils.Logger.Err(fmt.Sprintf("Function type %v not available, aborting execution!", a.ActionType)) diff --git a/engine/actions_test.go b/engine/actions_test.go index 88c3bcbb3..b96003200 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -38,7 +38,7 @@ var ( ) func TestActionTimingAlways(t *testing.T) { - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{StartTime: "00:00:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{StartTime: "00:00:00"}}} st := at.GetNextStartTime(referenceDate) y, m, d := referenceDate.Date() expected := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1) @@ -48,7 +48,7 @@ func TestActionTimingAlways(t *testing.T) { } func TestActionPlanNothing(t *testing.T) { - at := &ActionPlan{} + at := &ActionTiming{} st := at.GetNextStartTime(referenceDate) expected := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) if !st.Equal(expected) { @@ -57,7 +57,7 @@ func TestActionPlanNothing(t *testing.T) { } func TestActionTimingMidnight(t *testing.T) { - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{StartTime: "00:00:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{StartTime: "00:00:00"}}} y, m, d := referenceDate.Date() now := time.Date(y, m, d, 0, 0, 1, 0, time.Local) st := at.GetNextStartTime(now) @@ -68,7 +68,7 @@ func TestActionTimingMidnight(t *testing.T) { } func TestActionPlanOnlyHour(t *testing.T) { - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) y, m, d := now.Date() @@ -82,7 +82,7 @@ func TestActionPlanOnlyHour(t *testing.T) { } func TestActionPlanHourYear(t *testing.T) { - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2022}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2022}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) expected := time.Date(2022, 1, 1, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { @@ -91,7 +91,7 @@ func TestActionPlanHourYear(t *testing.T) { } func TestActionPlanOnlyWeekdays(t *testing.T) { - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{WeekDays: []time.Weekday{time.Monday}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{WeekDays: []time.Weekday{time.Monday}}}} st := at.GetNextStartTime(referenceDate) y, m, d := now.Date() @@ -112,7 +112,7 @@ func TestActionPlanOnlyWeekdays(t *testing.T) { } func TestActionPlanHourWeekdays(t *testing.T) { - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{WeekDays: []time.Weekday{time.Monday}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{WeekDays: []time.Weekday{time.Monday}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) y, m, d := now.Date() @@ -135,7 +135,7 @@ func TestActionPlanOnlyMonthdays(t *testing.T) { y, m, d := now.Date() tomorrow := time.Date(y, m, d, 0, 0, 0, 0, time.Local).AddDate(0, 0, 1) - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{MonthDays: utils.MonthDays{1, 25, 2, tomorrow.Day()}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{MonthDays: utils.MonthDays{1, 25, 2, tomorrow.Day()}}}} st := at.GetNextStartTime(referenceDate) expected := tomorrow if !st.Equal(expected) { @@ -151,7 +151,7 @@ func TestActionPlanHourMonthdays(t *testing.T) { if now.After(testTime) { y, m, d = tomorrow.Date() } - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) expected := time.Date(y, m, d, 10, 1, 0, 0, time.Local) if !st.Equal(expected) { @@ -163,7 +163,7 @@ func TestActionPlanOnlyMonths(t *testing.T) { y, m, _ := now.Date() nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{Months: utils.Months{time.February, time.May, nextMonth.Month()}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Months: utils.Months{time.February, time.May, nextMonth.Month()}}}} st := at.GetNextStartTime(referenceDate) expected := time.Date(nextMonth.Year(), nextMonth.Month(), 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { @@ -186,7 +186,7 @@ func TestActionPlanHourMonths(t *testing.T) { y = nextMonth.Year() } - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{ + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{ Months: utils.Months{now.Month(), nextMonth.Month()}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) @@ -216,7 +216,7 @@ func TestActionPlanHourMonthdaysMonths(t *testing.T) { month = nextMonth.Month() } } - at := &ActionPlan{Timing: &RateInterval{ + at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ Months: utils.Months{now.Month(), nextMonth.Month()}, MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, @@ -234,7 +234,7 @@ func TestActionPlanFirstOfTheMonth(t *testing.T) { y, m, _ := now.Date() nextMonth := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 1, 0) - at := &ActionPlan{Timing: &RateInterval{ + at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ MonthDays: utils.MonthDays{1}, }, @@ -249,7 +249,7 @@ func TestActionPlanFirstOfTheMonth(t *testing.T) { func TestActionPlanOnlyYears(t *testing.T) { y, _, _ := referenceDate.Date() nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{now.Year(), nextYear.Year()}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{now.Year(), nextYear.Year()}}}} st := at.GetNextStartTime(referenceDate) expected := nextYear if !st.Equal(expected) { @@ -258,7 +258,7 @@ func TestActionPlanOnlyYears(t *testing.T) { } func TestActionPlanPast(t *testing.T) { - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2023}}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{2023}}}} st := at.GetNextStartTime(referenceDate) expected := time.Date(2023, 1, 1, 0, 0, 0, 0, time.Local) if !st.Equal(expected) { @@ -267,7 +267,7 @@ func TestActionPlanPast(t *testing.T) { } func TestActionPlanHourYears(t *testing.T) { - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{referenceDate.Year(), referenceDate.Year() + 1}, StartTime: "10:01:00"}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{Years: utils.Years{referenceDate.Year(), referenceDate.Year() + 1}, StartTime: "10:01:00"}}} st := at.GetNextStartTime(referenceDate) expected := time.Date(referenceDate.Year(), 1, 1, 10, 1, 0, 0, time.Local) if referenceDate.After(expected) { @@ -292,7 +292,7 @@ func TestActionPlanHourMonthdaysYear(t *testing.T) { expected = tomorrow } } - at := &ActionPlan{Timing: &RateInterval{ + at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ Years: utils.Years{now.Year(), nextYear.Year()}, MonthDays: utils.MonthDays{now.Day(), tomorrow.Day()}, @@ -332,7 +332,7 @@ func TestActionPlanHourMonthdaysMonthYear(t *testing.T) { year = nextYear.Year() } } - at := &ActionPlan{Timing: &RateInterval{ + at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ Years: utils.Years{now.Year(), nextYear.Year()}, Months: utils.Months{now.Month(), nextMonth.Month()}, @@ -350,7 +350,7 @@ func TestActionPlanHourMonthdaysMonthYear(t *testing.T) { func TestActionPlanFirstOfTheYear(t *testing.T) { y, _, _ := now.Date() nextYear := time.Date(y, 1, 1, 0, 0, 0, 0, time.Local).AddDate(1, 0, 0) - at := &ActionPlan{Timing: &RateInterval{ + at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ Years: utils.Years{nextYear.Year()}, Months: utils.Months{time.January}, @@ -371,7 +371,7 @@ func TestActionPlanFirstMonthOfTheYear(t *testing.T) { if referenceDate.After(expected) { expected = expected.AddDate(1, 0, 0) } - at := &ActionPlan{Timing: &RateInterval{ + at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ Months: utils.Months{time.January}, }, @@ -388,7 +388,7 @@ func TestActionPlanFirstMonthOfTheYearSecondDay(t *testing.T) { if referenceDate.After(expected) { expected = expected.AddDate(1, 0, 0) } - at := &ActionPlan{Timing: &RateInterval{ + at := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ Months: utils.Months{time.January}, MonthDays: utils.MonthDays{2}, @@ -401,7 +401,7 @@ func TestActionPlanFirstMonthOfTheYearSecondDay(t *testing.T) { } func TestActionPlanCheckForASAP(t *testing.T) { - at := &ActionPlan{Timing: &RateInterval{Timing: &RITiming{StartTime: utils.ASAP}}} + at := &ActionTiming{Timing: &RateInterval{Timing: &RITiming{StartTime: utils.ASAP}}} if !at.IsASAP() { t.Errorf("%v should be asap!", at) } @@ -413,7 +413,7 @@ func TestActionPlanLogFunction(t *testing.T) { BalanceType: "test", Balance: &Balance{Value: 1.1}, } - at := &ActionPlan{ + at := &ActionTiming{ actions: []*Action{a}, } err := at.Execute() @@ -428,8 +428,8 @@ func TestActionPlanFunctionNotAvailable(t *testing.T) { BalanceType: "test", Balance: &Balance{Value: 1.1}, } - at := &ActionPlan{ - AccountIds: []string{"cgrates.org:dy"}, + at := &ActionTiming{ + accountIDs: map[string]struct{}{"cgrates.org:dy": struct{}{}}, Timing: &RateInterval{}, actions: []*Action{a}, } @@ -439,8 +439,8 @@ func TestActionPlanFunctionNotAvailable(t *testing.T) { } } -func TestActionPlanPriotityListSortByWeight(t *testing.T) { - at1 := &ActionPlan{Timing: &RateInterval{ +func TestActionTimingPriorityListSortByWeight(t *testing.T) { + at1 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ Years: utils.Years{2020}, Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, @@ -449,7 +449,7 @@ func TestActionPlanPriotityListSortByWeight(t *testing.T) { }, Weight: 20, }} - at2 := &ActionPlan{Timing: &RateInterval{ + at2 := &ActionTiming{Timing: &RateInterval{ Timing: &RITiming{ Years: utils.Years{2020}, Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, @@ -458,7 +458,7 @@ func TestActionPlanPriotityListSortByWeight(t *testing.T) { }, Weight: 10, }} - var atpl ActionPlanPriotityList + var atpl ActionTimingPriorityList atpl = append(atpl, at2, at1) atpl.Sort() if atpl[0] != at1 || atpl[1] != at2 { @@ -466,8 +466,8 @@ func TestActionPlanPriotityListSortByWeight(t *testing.T) { } } -func TestActionPlanPriotityListWeight(t *testing.T) { - at1 := &ActionPlan{ +func TestActionTimingPriorityListWeight(t *testing.T) { + at1 := &ActionTiming{ Timing: &RateInterval{ Timing: &RITiming{ Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, @@ -477,7 +477,7 @@ func TestActionPlanPriotityListWeight(t *testing.T) { }, Weight: 20, } - at2 := &ActionPlan{ + at2 := &ActionTiming{ Timing: &RateInterval{ Timing: &RITiming{ Months: utils.Months{time.January, time.February, time.March, time.April, time.May, time.June, time.July, time.August, time.September, time.October, time.November, time.December}, @@ -487,7 +487,7 @@ func TestActionPlanPriotityListWeight(t *testing.T) { }, Weight: 10, } - var atpl ActionPlanPriotityList + var atpl ActionTimingPriorityList atpl = append(atpl, at2, at1) atpl.Sort() if atpl[0] != at1 || atpl[1] != at2 { @@ -495,17 +495,18 @@ func TestActionPlanPriotityListWeight(t *testing.T) { } } +/* func TestActionPlansRemoveMember(t *testing.T) { at1 := &ActionPlan{ Uuid: "some uuid", Id: "test", - AccountIds: []string{"one", "two", "three"}, + AccountIDs: []string{"one", "two", "three"}, ActionsId: "TEST_ACTIONS", } at2 := &ActionPlan{ Uuid: "some uuid22", Id: "test2", - AccountIds: []string{"three", "four"}, + AccountIDs: []string{"three", "four"}, ActionsId: "TEST_ACTIONS2", } ats := ActionPlans{at1, at2} @@ -522,7 +523,7 @@ func TestActionPlansRemoveMember(t *testing.T) { if ats2 = RemActionPlan(ats2, "", ""); len(ats2) != 0 { t.Error("Should have no members anymore", ats2) } -} +}*/ func TestActionTriggerMatchNil(t *testing.T) { at := &ActionTrigger{ @@ -1056,10 +1057,8 @@ func TestActionPlanLogging(t *testing.T) { Rates: RateGroups{&Rate{0, 1.0, 1 * time.Second, 60 * time.Second}}, }, } - at := &ActionPlan{ - Uuid: "some uuid", - Id: "test", - AccountIds: []string{"one", "two", "three"}, + at := &ActionTiming{ + accountIDs: map[string]struct{}{"one": struct{}{}, "two": struct{}{}, "three": struct{}{}}, Timing: i, Weight: 10.0, ActionsId: "TEST_ACTIONS", @@ -1068,7 +1067,7 @@ func TestActionPlanLogging(t *testing.T) { if err != nil { t.Error("Error getting actions for the action trigger: ", err) } - storageLogger.LogActionPlan(utils.SCHED_SOURCE, at, as) + storageLogger.LogActionTiming(utils.SCHED_SOURCE, at, as) //expected := "some uuid|test|one,two,three|;1,2,3,4,5,6,7,8,9,10,11,12;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31;1,2,3,4,5;18:00:00;00:00:00;10;0;1;60;1|10|TEST_ACTIONS*|TOPUP|MONETARY|OUT|10|0" var key string atMap, _ := ratingStorage.GetAllActionPlans() @@ -1104,8 +1103,8 @@ func TestRemoveAction(t *testing.T) { ActionType: REMOVE_ACCOUNT, } - at := &ActionPlan{ - AccountIds: []string{"cgrates.org:remo"}, + at := &ActionTiming{ + accountIDs: map[string]struct{}{"cgrates.org:remo": struct{}{}}, actions: Actions{a}, } at.Execute() @@ -1123,8 +1122,8 @@ func TestTopupAction(t *testing.T) { Balance: &Balance{Value: 25, DestinationIds: utils.NewStringMap("RET"), Directions: utils.NewStringMap(utils.OUT), Weight: 20}, } - at := &ActionPlan{ - AccountIds: []string{"vdf:minu"}, + at := &ActionTiming{ + accountIDs: map[string]struct{}{"vdf:minu": struct{}{}}, actions: Actions{a}, } @@ -1145,8 +1144,8 @@ func TestTopupActionLoaded(t *testing.T) { Balance: &Balance{Value: 25, DestinationIds: utils.NewStringMap("RET"), Directions: utils.NewStringMap(utils.OUT), Weight: 20}, } - at := &ActionPlan{ - AccountIds: []string{"vdf:minitsboy"}, + at := &ActionTiming{ + accountIDs: map[string]struct{}{"vdf:minitsboy": struct{}{}}, actions: Actions{a}, } @@ -1297,8 +1296,8 @@ func TestActionTransactionFuncType(t *testing.T) { if err != nil { t.Error("Error setting account: ", err) } - at := &ActionPlan{ - AccountIds: []string{"cgrates.org:trans"}, + at := &ActionTiming{ + accountIDs: map[string]struct{}{"cgrates.org:trans": struct{}{}}, Timing: &RateInterval{}, actions: []*Action{ &Action{ @@ -1335,8 +1334,8 @@ func TestActionTransactionBalanceType(t *testing.T) { if err != nil { t.Error("Error setting account: ", err) } - at := &ActionPlan{ - AccountIds: []string{"cgrates.org:trans"}, + at := &ActionTiming{ + accountIDs: map[string]struct{}{"cgrates.org:trans": struct{}{}}, Timing: &RateInterval{}, actions: []*Action{ &Action{ @@ -1373,8 +1372,8 @@ func TestActionWithExpireWithoutExpire(t *testing.T) { if err != nil { t.Error("Error setting account: ", err) } - at := &ActionPlan{ - AccountIds: []string{"cgrates.org:exp"}, + at := &ActionTiming{ + accountIDs: map[string]struct{}{"cgrates.org:exp": struct{}{}}, Timing: &RateInterval{}, actions: []*Action{ &Action{ @@ -1428,8 +1427,8 @@ func TestActionRemoveBalance(t *testing.T) { if err != nil { t.Error("Error setting account: ", err) } - at := &ActionPlan{ - AccountIds: []string{"cgrates.org:rembal"}, + at := &ActionTiming{ + accountIDs: map[string]struct{}{"cgrates.org:rembal": struct{}{}}, Timing: &RateInterval{}, actions: []*Action{ &Action{ diff --git a/engine/calldesc_test.go b/engine/calldesc_test.go index 2e8744fcd..b33807f38 100644 --- a/engine/calldesc_test.go +++ b/engine/calldesc_test.go @@ -487,8 +487,9 @@ func TestMaxSessionTimeWithAccount(t *testing.T) { } func TestMaxSessionTimeWithMaxRate(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } //acc, _ := accountingStorage.GetAccount("cgrates.org:12345") @@ -513,8 +514,9 @@ func TestMaxSessionTimeWithMaxRate(t *testing.T) { } func TestMaxSessionTimeWithMaxCost(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -536,8 +538,9 @@ func TestMaxSessionTimeWithMaxCost(t *testing.T) { } func TestGetCostWithMaxCost(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -558,8 +561,9 @@ func TestGetCostWithMaxCost(t *testing.T) { } } func TestGetCostRoundingIssue(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -582,8 +586,9 @@ func TestGetCostRoundingIssue(t *testing.T) { } func TestGetCostRatingInfoOnZeroTime(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -609,8 +614,9 @@ func TestGetCostRatingInfoOnZeroTime(t *testing.T) { } func TestDebitRatingInfoOnZeroTime(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -637,8 +643,9 @@ func TestDebitRatingInfoOnZeroTime(t *testing.T) { } func TestMaxDebitRatingInfoOnZeroTime(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -664,8 +671,9 @@ func TestMaxDebitRatingInfoOnZeroTime(t *testing.T) { } func TestMaxDebitUnknowDest(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -686,8 +694,9 @@ func TestMaxDebitUnknowDest(t *testing.T) { } func TestGetCostMaxDebitRoundingIssue(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -718,8 +727,9 @@ func TestGetCostMaxDebitRoundingIssue(t *testing.T) { } func TestMaxSessionTimeWithMaxCostFree(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -741,8 +751,9 @@ func TestMaxSessionTimeWithMaxCostFree(t *testing.T) { } func TestMaxDebitWithMaxCostFree(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -764,8 +775,9 @@ func TestMaxDebitWithMaxCostFree(t *testing.T) { } func TestGetCostWithMaxCostFree(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd := &CallDescriptor{ @@ -818,12 +830,14 @@ func TestMaxSessionTimeWithAccountAlias(t *testing.T) { } func TestMaxSessionTimeWithAccountShared(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP_SHARED0_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP_SHARED0_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } - ap, _ = ratingStorage.GetActionPlans("TOPUP_SHARED10_AT", false) - for _, at := range ap { + ap, _ = ratingStorage.GetActionPlan("TOPUP_SHARED10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } @@ -857,12 +871,14 @@ func TestMaxSessionTimeWithAccountShared(t *testing.T) { } func TestMaxDebitWithAccountShared(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP_SHARED0_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP_SHARED0_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } - ap, _ = ratingStorage.GetActionPlans("TOPUP_SHARED10_AT", false) - for _, at := range ap { + ap, _ = ratingStorage.GetActionPlan("TOPUP_SHARED10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } @@ -1077,8 +1093,9 @@ func TestMaxSesionTimeLongerThanMoney(t *testing.T) { } func TestDebitFromShareAndNormal(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP_SHARED10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP_SHARED10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } @@ -1105,8 +1122,9 @@ func TestDebitFromShareAndNormal(t *testing.T) { } func TestDebitFromEmptyShare(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP_EMPTY_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP_EMPTY_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } @@ -1133,8 +1151,9 @@ func TestDebitFromEmptyShare(t *testing.T) { } func TestDebitNegatve(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("POST_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("POST_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } @@ -1172,8 +1191,9 @@ func TestDebitNegatve(t *testing.T) { } func TestMaxDebitZeroDefinedRate(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd1 := &CallDescriptor{ @@ -1200,8 +1220,9 @@ func TestMaxDebitZeroDefinedRate(t *testing.T) { } func TestMaxDebitZeroDefinedRateOnlyMinutes(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd1 := &CallDescriptor{ @@ -1228,8 +1249,9 @@ func TestMaxDebitZeroDefinedRateOnlyMinutes(t *testing.T) { } func TestMaxDebitConsumesMinutes(t *testing.T) { - ap, _ := ratingStorage.GetActionPlans("TOPUP10_AT", false) - for _, at := range ap { + ap, _ := ratingStorage.GetActionPlan("TOPUP10_AT", false) + for _, at := range ap.ActionTimings { + at.accountIDs = ap.AccountIDs at.Execute() } cd1 := &CallDescriptor{ diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index eb6a1bdfa..e01df4be7 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -985,25 +985,42 @@ func TestLoadActionTimings(t *testing.T) { if len(csvr.actionPlans) != 6 { t.Error("Failed to load action timings: ", len(csvr.actionPlans)) } - atm := csvr.actionPlans["MORE_MINUTES"][0] + atm := csvr.actionPlans["MORE_MINUTES"] expected := &ActionPlan{ Uuid: atm.Uuid, Id: "MORE_MINUTES", - AccountIds: []string{"vdf:minitsboy"}, - Timing: &RateInterval{ - Timing: &RITiming{ - Years: utils.Years{2012}, - Months: utils.Months{}, - MonthDays: utils.MonthDays{}, - WeekDays: utils.WeekDays{}, - StartTime: utils.ASAP, + AccountIDs: map[string]struct{}{"vdf:minitsboy": struct{}{}}, + ActionTimings: []*ActionTiming{ + &ActionTiming{ + Timing: &RateInterval{ + Timing: &RITiming{ + Years: utils.Years{2012}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{}, + StartTime: utils.ASAP, + }, + }, + Weight: 10, + ActionsId: "MINI", + }, + &ActionTiming{ + Timing: &RateInterval{ + Timing: &RITiming{ + Years: utils.Years{2012}, + Months: utils.Months{}, + MonthDays: utils.MonthDays{}, + WeekDays: utils.WeekDays{}, + StartTime: utils.ASAP, + }, + }, + Weight: 10, + ActionsId: "SHARED", }, }, - Weight: 10, - ActionsId: "MINI", } if !reflect.DeepEqual(atm, expected) { - t.Errorf("Error loading action timing:\n%+v", atm) + t.Errorf("Error loading action timing:\n%+v", atm.ActionTimings[1].Timing) } } diff --git a/engine/storage_interface.go b/engine/storage_interface.go index 8c51db8ea..916cd511c 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -63,9 +63,9 @@ type RatingStorage interface { SetSharedGroup(*SharedGroup) error GetActionTriggers(string) (ActionTriggers, error) SetActionTriggers(string, ActionTriggers) error - GetActionPlans(string, bool) (ActionPlans, error) - SetActionPlans(string, ActionPlans) error - GetAllActionPlans() (map[string]ActionPlans, error) + GetActionPlan(string, bool) (*ActionPlan, error) + SetActionPlan(string, *ActionPlan) error + GetAllActionPlans() (map[string]*ActionPlan, error) } type AccountingStorage interface { @@ -106,7 +106,7 @@ type LogStorage interface { Storage //GetAllActionTimingsLogs() (map[string]ActionsTimings, error) LogActionTrigger(ubId, source string, at *ActionTrigger, as Actions) error - LogActionPlan(source string, at *ActionPlan, as Actions) error + LogActionTiming(source string, at *ActionTiming, as Actions) error } type LoadStorage interface { diff --git a/engine/storage_map.go b/engine/storage_map.go index adf785a69..776ffcaff 100644 --- a/engine/storage_map.go +++ b/engine/storage_map.go @@ -178,7 +178,7 @@ func (ms *MapStorage) cacheRating(dKeys, rpKeys, rpfKeys, lcrKeys, dcsKeys, actK } if strings.HasPrefix(k, utils.ACTION_PLAN_PREFIX) { cache2go.RemKey(k) - if _, err := ms.GetActionPlans(k[len(utils.ACTION_PLAN_PREFIX):], true); err != nil { + if _, err := ms.GetActionPlan(k[len(utils.ACTION_PLAN_PREFIX):], true); err != nil { cache2go.RollbackTransaction() return err } @@ -645,11 +645,11 @@ func (ms *MapStorage) SetActionTriggers(key string, atrs ActionTriggers) (err er return } -func (ms *MapStorage) GetActionPlans(key string, skipCache bool) (ats ActionPlans, err error) { +func (ms *MapStorage) GetActionPlan(key string, skipCache bool) (ats *ActionPlan, err error) { key = utils.ACTION_PLAN_PREFIX + key if !skipCache { if x, err := cache2go.Get(key); err == nil { - return x.(ActionPlans), nil + return x.(*ActionPlan), nil } else { return nil, err } @@ -663,8 +663,8 @@ func (ms *MapStorage) GetActionPlans(key string, skipCache bool) (ats ActionPlan return } -func (ms *MapStorage) SetActionPlans(key string, ats ActionPlans) (err error) { - if len(ats) == 0 { +func (ms *MapStorage) SetActionPlan(key string, ats *ActionPlan) (err error) { + if len(ats.ActionTimings) == 0 { // delete the key delete(ms.dict, utils.ACTION_PLAN_PREFIX+key) cache2go.RemKey(utils.ACTION_PLAN_PREFIX + key) @@ -675,15 +675,15 @@ func (ms *MapStorage) SetActionPlans(key string, ats ActionPlans) (err error) { return } -func (ms *MapStorage) GetAllActionPlans() (ats map[string]ActionPlans, err error) { +func (ms *MapStorage) GetAllActionPlans() (ats map[string]*ActionPlan, err error) { apls, err := cache2go.GetAllEntries(utils.ACTION_PLAN_PREFIX) if err != nil { return nil, err } - ats = make(map[string]ActionPlans, len(apls)) + ats = make(map[string]*ActionPlan, len(apls)) for key, value := range apls { - apl := value.(ActionPlans) + apl := value.(*ActionPlan) ats[key] = apl } @@ -774,7 +774,7 @@ func (ms *MapStorage) LogActionTrigger(ubId, source string, at *ActionTrigger, a return } -func (ms *MapStorage) LogActionPlan(source string, at *ActionPlan, as Actions) (err error) { +func (ms *MapStorage) LogActionTiming(source string, at *ActionTiming, as Actions) (err error) { mat, err := ms.ms.Marshal(at) if err != nil { return diff --git a/engine/storage_mongo.go b/engine/storage_mongo.go index 5ea101224..510442356 100644 --- a/engine/storage_mongo.go +++ b/engine/storage_mongo.go @@ -451,7 +451,7 @@ func (ms *MongoStorage) cacheRating(dKeys, rpKeys, rpfKeys, lcrKeys, dcsKeys, ac } for _, key := range aplKeys { cache2go.RemKey(key) - if _, err = ms.GetActionPlans(key[len(utils.ACTION_PLAN_PREFIX):], true); err != nil { + if _, err = ms.GetActionPlan(key[len(utils.ACTION_PLAN_PREFIX):], true); err != nil { cache2go.RollbackTransaction() return err } @@ -1026,17 +1026,17 @@ func (ms *MongoStorage) SetActionTriggers(key string, atrs ActionTriggers) (err return err } -func (ms *MongoStorage) GetActionPlans(key string, skipCache bool) (ats ActionPlans, err error) { +func (ms *MongoStorage) GetActionPlan(key string, skipCache bool) (ats *ActionPlan, err error) { if !skipCache { if x, err := cache2go.Get(utils.ACTION_PLAN_PREFIX + key); err == nil { - return x.(ActionPlans), nil + return x.(*ActionPlan), nil } else { return nil, err } } var kv struct { Key string - Value ActionPlans + Value *ActionPlan } err = ms.db.C(colApl).Find(bson.M{"key": key}).One(&kv) if err == nil { @@ -1046,8 +1046,8 @@ func (ms *MongoStorage) GetActionPlans(key string, skipCache bool) (ats ActionPl return } -func (ms *MongoStorage) SetActionPlans(key string, ats ActionPlans) error { - if len(ats) == 0 { +func (ms *MongoStorage) SetActionPlan(key string, ats *ActionPlan) error { + if len(ats.ActionTimings) == 0 { cache2go.RemKey(utils.ACTION_PLAN_PREFIX + key) err := ms.db.C(colApl).Remove(bson.M{"key": key}) if err != mgo.ErrNotFound { @@ -1057,20 +1057,20 @@ func (ms *MongoStorage) SetActionPlans(key string, ats ActionPlans) error { } _, err := ms.db.C(colApl).Upsert(bson.M{"key": key}, &struct { Key string - Value ActionPlans + Value *ActionPlan }{Key: key, Value: ats}) return err } -func (ms *MongoStorage) GetAllActionPlans() (ats map[string]ActionPlans, err error) { +func (ms *MongoStorage) GetAllActionPlans() (ats map[string]*ActionPlan, err error) { apls, err := cache2go.GetAllEntries(utils.ACTION_PLAN_PREFIX) if err != nil { return nil, err } - ats = make(map[string]ActionPlans, len(apls)) + ats = make(map[string]*ActionPlan, len(apls)) for key, value := range apls { - apl := value.(ActionPlans) + apl := value.(*ActionPlan) ats[key] = apl } diff --git a/engine/storage_mongo_tp.go b/engine/storage_mongo_tp.go index 9a30c5287..7a1eda6b4 100644 --- a/engine/storage_mongo_tp.go +++ b/engine/storage_mongo_tp.go @@ -689,9 +689,9 @@ func (ms *MongoStorage) LogActionTrigger(ubId, source string, at *ActionTrigger, }{ubId, at, as, time.Now(), source}) } -func (ms *MongoStorage) LogActionPlan(source string, at *ActionPlan, as Actions) (err error) { +func (ms *MongoStorage) LogActionTiming(source string, at *ActionTiming, as Actions) (err error) { return ms.db.C(colLogApl).Insert(&struct { - ActionPlan *ActionPlan + ActionPlan *ActionTiming Actions Actions LogTime time.Time Source string diff --git a/engine/storage_redis.go b/engine/storage_redis.go index d93a59d14..e8bb6d493 100644 --- a/engine/storage_redis.go +++ b/engine/storage_redis.go @@ -282,7 +282,7 @@ func (rs *RedisStorage) cacheRating(dKeys, rpKeys, rpfKeys, lcrKeys, dcsKeys, ac } for _, key := range aplKeys { cache2go.RemKey(key) - if _, err = rs.GetActionPlans(key[len(utils.ACTION_PLAN_PREFIX):], true); err != nil { + if _, err = rs.GetActionPlan(key[len(utils.ACTION_PLAN_PREFIX):], true); err != nil { cache2go.RollbackTransaction() return err } @@ -893,11 +893,11 @@ func (rs *RedisStorage) SetActionTriggers(key string, atrs ActionTriggers) (err return conn.Cmd("SET", utils.ACTION_TRIGGER_PREFIX+key, result).Err } -func (rs *RedisStorage) GetActionPlans(key string, skipCache bool) (ats ActionPlans, err error) { +func (rs *RedisStorage) GetActionPlan(key string, skipCache bool) (ats *ActionPlan, err error) { key = utils.ACTION_PLAN_PREFIX + key if !skipCache { if x, err := cache2go.Get(key); err == nil { - return x.(ActionPlans), nil + return x.(*ActionPlan), nil } else { return nil, err } @@ -911,8 +911,8 @@ func (rs *RedisStorage) GetActionPlans(key string, skipCache bool) (ats ActionPl return } -func (rs *RedisStorage) SetActionPlans(key string, ats ActionPlans) (err error) { - if len(ats) == 0 { +func (rs *RedisStorage) SetActionPlan(key string, ats *ActionPlan) (err error) { + if len(ats.ActionTimings) == 0 { // delete the key err = rs.db.Cmd("DEL", utils.ACTION_PLAN_PREFIX+key).Err cache2go.RemKey(utils.ACTION_PLAN_PREFIX + key) @@ -925,15 +925,15 @@ func (rs *RedisStorage) SetActionPlans(key string, ats ActionPlans) (err error) return rs.db.Cmd("SET", utils.ACTION_PLAN_PREFIX+key, result).Err } -func (rs *RedisStorage) GetAllActionPlans() (ats map[string]ActionPlans, err error) { +func (rs *RedisStorage) GetAllActionPlans() (ats map[string]*ActionPlan, err error) { apls, err := cache2go.GetAllEntries(utils.ACTION_PLAN_PREFIX) if err != nil { return nil, err } - ats = make(map[string]ActionPlans, len(apls)) + ats = make(map[string]*ActionPlan, len(apls)) for key, value := range apls { - apl := value.(ActionPlans) + apl := value.(*ActionPlan) ats[key] = apl } diff --git a/engine/storage_sql.go b/engine/storage_sql.go index 9e550d066..2c0336e90 100644 --- a/engine/storage_sql.go +++ b/engine/storage_sql.go @@ -592,7 +592,7 @@ func (self *SQLStorage) GetCallCostLog(cgrid, source, runid string) (*CallCost, func (self *SQLStorage) LogActionTrigger(ubId, source string, at *ActionTrigger, as Actions) (err error) { return } -func (self *SQLStorage) LogActionPlan(source string, at *ActionPlan, as Actions) (err error) { +func (self *SQLStorage) LogActionTiming(source string, at *ActionTiming, as Actions) (err error) { return } diff --git a/engine/tp_reader.go b/engine/tp_reader.go index a44248459..912d1a629 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -19,7 +19,7 @@ type TpReader struct { accountingStorage AccountingStorage lr LoadReader actions map[string][]*Action - actionPlans map[string][]*ActionPlan + actionPlans map[string]*ActionPlan actionsTriggers map[string]ActionTriggers accountActions map[string]*Account dirtyRpAliases []*TenantRatingSubject // used to clean aliases that might have changed @@ -73,7 +73,7 @@ func NewTpReader(rs RatingStorage, as AccountingStorage, lr LoadReader, tpid, ti func (tpr *TpReader) Init() { tpr.actions = make(map[string][]*Action) - tpr.actionPlans = make(map[string][]*ActionPlan) + tpr.actionPlans = make(map[string]*ActionPlan) tpr.actionsTriggers = make(map[string]ActionTriggers) tpr.rates = make(map[string]*utils.TPRate) tpr.destinations = make(map[string]*Destination) @@ -575,9 +575,14 @@ func (tpr *TpReader) LoadActionPlans() (err error) { if !exists { return fmt.Errorf("[ActionPlans] Could not load the timing for tag: %v", at.TimingId) } - actPln := &ActionPlan{ - Uuid: utils.GenUUID(), - Id: atId, + var actPln *ActionPlan + if actPln, exists = tpr.actionPlans[atId]; !exists { + actPln = &ActionPlan{ + Uuid: utils.GenUUID(), + Id: atId, + } + } + actPln.ActionTimings = append(actPln.ActionTimings, &ActionTiming{ Weight: at.Weight, Timing: &RateInterval{ Timing: &RITiming{ @@ -589,8 +594,9 @@ func (tpr *TpReader) LoadActionPlans() (err error) { }, }, ActionsId: at.ActionsId, - } - tpr.actionPlans[atId] = append(tpr.actionPlans[atId], actPln) + }) + + tpr.actionPlans[atId] = actPln } } @@ -660,11 +666,10 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error // action timings if accountAction.ActionPlanId != "" { // get old userBalanceIds - var exitingAccountIds []string - existingActionPlans, err := tpr.ratingStorage.GetActionPlans(accountAction.ActionPlanId, true) - if err == nil && len(existingActionPlans) > 0 { - // all action timings from a specific tag shuld have the same list of user balances from the first one - exitingAccountIds = existingActionPlans[0].AccountIds + var exitingAccountIds map[string]struct{} + existingActionPlan, err := tpr.ratingStorage.GetActionPlan(accountAction.ActionPlanId, true) + if err == nil && existingActionPlan != nil { + exitingAccountIds = existingActionPlan.AccountIDs } tpap, err := tpr.lr.GetTpActionPlans(tpr.tpid, accountAction.ActionPlanId) @@ -677,7 +682,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error if err != nil { return err } - var actionTimings []*ActionPlan + var actionPlan *ActionPlan ats := aps[accountAction.ActionPlanId] for _, at := range ats { // Check action exists before saving it inside actionTiming key @@ -703,9 +708,13 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error } else { t = tpr.timings[at.TimingId] // *asap } - actPln := &ActionPlan{ - Uuid: utils.GenUUID(), - Id: accountAction.ActionPlanId, + if actionPlan == nil { + actionPlan = &ActionPlan{ + Uuid: utils.GenUUID(), + Id: accountAction.ActionPlanId, + } + } + actionPlan.ActionTimings = append(actionPlan.ActionTimings, &ActionTiming{ Weight: at.Weight, Timing: &RateInterval{ Timing: &RITiming{ @@ -716,25 +725,15 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error }, }, ActionsId: at.ActionsId, - } + }) // collect action ids from timings - actionsIds = append(actionsIds, actPln.ActionsId) - //add user balance id if no already in - found := false - for _, ubId := range exitingAccountIds { - if ubId == id { - found = true - break - } - } - if !found { - actPln.AccountIds = append(exitingAccountIds, id) - } - actionTimings = append(actionTimings, actPln) + actionsIds = append(actionsIds, at.ActionsId) + exitingAccountIds[id] = struct{}{} + actionPlan.AccountIDs = exitingAccountIds } - // write action triggers - err = tpr.ratingStorage.SetActionPlans(accountAction.ActionPlanId, actionTimings) + // write action plan + err = tpr.ratingStorage.SetActionPlan(accountAction.ActionPlanId, actionPlan) if err != nil { return errors.New(err.Error() + " (SetActionPlan): " + accountAction.ActionPlanId) } @@ -883,14 +882,15 @@ func (tpr *TpReader) LoadAccountActions() (err error) { } ub.InitCounters() tpr.accountActions[aa.KeyId()] = ub - aTimings, exists := tpr.actionPlans[aa.ActionPlanId] + actionPlan, exists := tpr.actionPlans[aa.ActionPlanId] if !exists { log.Printf("could not get action plan for tag %v", aa.ActionPlanId) // must not continue here } - for _, at := range aTimings { - at.AccountIds = append(at.AccountIds, aa.KeyId()) + if actionPlan.AccountIDs == nil { + actionPlan.AccountIDs = make(map[string]struct{}) } + actionPlan.AccountIDs[aa.KeyId()] = struct{}{} } return nil } @@ -1319,7 +1319,7 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose bool) (err error) { log.Print("Action Plans:") } for k, ats := range tpr.actionPlans { - err = tpr.ratingStorage.SetActionPlans(k, ats) + err = tpr.ratingStorage.SetActionPlan(k, ats) if err != nil { return err }