diff --git a/rater/action.go b/rater/action.go
index e0af15d3d..2cc8e66db 100644
--- a/rater/action.go
+++ b/rater/action.go
@@ -21,8 +21,6 @@ package rater
import (
"fmt"
"sort"
- "strconv"
- "strings"
)
/*
@@ -38,6 +36,8 @@ type Action struct {
MinuteBucket *MinuteBucket
}
+type Actions []*Action
+
type actionTypeFunc func(*UserBalance, *Action) error
func getActionFunc(typ string) (actionTypeFunc, bool) {
@@ -194,40 +194,3 @@ func (apl ActionPriotityList) Less(i, j int) bool {
func (apl ActionPriotityList) Sort() {
sort.Sort(apl)
}
-
-/*
-Serializes the action for the storage. Used for key-value storages.
-*/
-func (a *Action) store() (result string) {
- result += a.Id + "|"
- result += a.ActionType + "|"
- result += a.BalanceId + "|"
- result += a.Direction + "|"
- result += strconv.FormatFloat(a.Units, 'f', -1, 64) + "|"
- result += strconv.FormatFloat(a.Weight, 'f', -1, 64)
- if a.MinuteBucket != nil {
- result += "|"
- result += a.MinuteBucket.store()
- }
- return
-}
-
-/*
-De-serializes the action for the storage. Used for key-value storages.
-*/
-func (a *Action) restore(input string) {
- elements := strings.Split(input, "|")
- if len(elements) < 6 {
- return
- }
- a.Id = elements[0]
- a.ActionType = elements[1]
- a.BalanceId = elements[2]
- a.Direction = elements[3]
- a.Units, _ = strconv.ParseFloat(elements[4], 64)
- a.Weight, _ = strconv.ParseFloat(elements[5], 64)
- if len(elements) == 7 {
- a.MinuteBucket = &MinuteBucket{}
- a.MinuteBucket.restore(elements[6])
- }
-}
diff --git a/rater/action_timing.go b/rater/action_timing.go
index 22913b25f..13e69d094 100644
--- a/rater/action_timing.go
+++ b/rater/action_timing.go
@@ -45,6 +45,8 @@ type ActionTiming struct {
stCache time.Time
}
+type ActionTimings []*ActionTiming
+
func (at *ActionTiming) GetNextStartTime() (t time.Time) {
if !at.stCache.IsZero() {
return at.stCache
@@ -277,45 +279,6 @@ func (at *ActionTiming) String() string {
return at.Tag + " " + at.GetNextStartTime().String() + ",w: " + strconv.FormatFloat(at.Weight, 'f', -1, 64)
}
-/*
-Serializes the action timing for the storage. Used for key-value storages.
-*/
-func (at *ActionTiming) store() (result string) {
- result += at.Id + "|"
- result += at.Tag + "|"
- for _, ubi := range at.UserBalanceIds {
- result += ubi + ","
- }
- result = strings.TrimRight(result, ",") + "|"
- if at.Timing != nil {
- result += at.Timing.store() + "|"
- } else {
- result += " |"
- }
- result += strconv.FormatFloat(at.Weight, 'f', -1, 64) + "|"
- result += at.ActionsId
- return
-}
-
-/*
-De-serializes the action timing for the storage. Used for key-value storages.
-*/
-func (at *ActionTiming) restore(input string) {
- elements := strings.Split(input, "|")
- at.Id = elements[0]
- at.Tag = elements[1]
- for _, ubi := range strings.Split(elements[2], ",") {
- if strings.TrimSpace(ubi) != "" {
- at.UserBalanceIds = append(at.UserBalanceIds, ubi)
- }
- }
-
- at.Timing = &Interval{}
- at.Timing.restore(elements[3])
- at.Weight, _ = strconv.ParseFloat(elements[4], 64)
- at.ActionsId = elements[5]
-}
-
// helper function for uuid generation
func GenUUID() string {
uuid := make([]byte, 16)
diff --git a/rater/action_trigger.go b/rater/action_trigger.go
index 1728005cb..9a98df131 100644
--- a/rater/action_trigger.go
+++ b/rater/action_trigger.go
@@ -22,8 +22,6 @@ import (
"fmt"
//"log"
"sort"
- "strconv"
- "strings"
)
type ActionTrigger struct {
@@ -79,36 +77,3 @@ func (atpl ActionTriggerPriotityList) Less(i, j int) bool {
func (atpl ActionTriggerPriotityList) Sort() {
sort.Sort(atpl)
}
-
-/*
-Serializes the action trigger for the storage. Used for key-value storages.
-*/
-func (at *ActionTrigger) store() (result string) {
- result += at.Id + ";"
- result += at.BalanceId + ";"
- result += at.Direction + ";"
- result += at.DestinationId + ";"
- result += at.ActionsId + ";"
- result += strconv.FormatFloat(at.ThresholdValue, 'f', -1, 64) + ";"
- result += strconv.FormatFloat(at.Weight, 'f', -1, 64) + ";"
- result += strconv.FormatBool(at.Executed)
- return
-}
-
-/*
-De-serializes the action timing for the storage. Used for key-value storages.
-*/
-func (at *ActionTrigger) restore(input string) {
- elements := strings.Split(input, ";")
- if len(elements) != 8 {
- return
- }
- at.Id = elements[0]
- at.BalanceId = elements[1]
- at.Direction = elements[2]
- at.DestinationId = elements[3]
- at.ActionsId = elements[4]
- at.ThresholdValue, _ = strconv.ParseFloat(elements[5], 64)
- at.Weight, _ = strconv.ParseFloat(elements[6], 64)
- at.Executed, _ = strconv.ParseBool(elements[7])
-}
diff --git a/rater/actions_test.go b/rater/actions_test.go
index b1e651683..62078c8b6 100644
--- a/rater/actions_test.go
+++ b/rater/actions_test.go
@@ -19,64 +19,10 @@ along with this program. If not, see
package rater
import (
- "reflect"
- //"strings"
"testing"
"time"
)
-func TestActionTimingStoreRestore(t *testing.T) {
- i := &Interval{
- Months: 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},
- MonthDays: MonthDays{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},
- WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
- StartTime: "18:00:00",
- EndTime: "00:00:00",
- Weight: 10.0,
- ConnectFee: 0.0,
- Price: 1.0,
- PricedUnits: 60,
- RateIncrements: 1,
- }
- at := &ActionTiming{
- Id: "some uuid",
- Tag: "test",
- UserBalanceIds: []string{"one", "two", "three"},
- Timing: i,
- Weight: 10.0,
- ActionsId: "Commando",
- }
- r := at.store()
- if string(r) != "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|Commando" {
- t.Errorf("Error serializing action timing: %v", string(r))
- }
- o := &ActionTiming{}
- o.restore(r)
- if !reflect.DeepEqual(o, at) {
- t.Errorf("Expected %v was %v", at, o)
- }
-}
-func TestActionTriggerStoreRestore(t *testing.T) {
- at := &ActionTrigger{
- Id: "some_uuid",
- BalanceId: CREDIT,
- Direction: OUTBOUND,
- ThresholdValue: 100.0,
- DestinationId: "NAT",
- Weight: 10.0,
- ActionsId: "Commando",
- }
- r := at.store()
- if string(r) != "some_uuid;MONETARY;OUT;NAT;Commando;100;10;false" {
- t.Errorf("Error serializing action trigger: %v", string(r))
- }
- o := &ActionTrigger{}
- o.restore(r)
- if !reflect.DeepEqual(o, at) {
- t.Errorf("Expected %v was %v", at, o)
- }
-}
-
func TestActionTimingNothing(t *testing.T) {
at := &ActionTiming{}
st := at.GetNextStartTime()
diff --git a/rater/activationperiod_test.go b/rater/activationperiod_test.go
index 8e1c216e2..c3a5866c9 100644
--- a/rater/activationperiod_test.go
+++ b/rater/activationperiod_test.go
@@ -161,7 +161,7 @@ func BenchmarkActivationPeriodStoreRestoreJson(b *testing.B) {
func BenchmarkActivationPeriodRestore(b *testing.B) {
ap := &ActivationPeriod{}
for i := 0; i < b.N; i++ {
- activationPeriodRestore("1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0", ap)
+ ap.Restore("1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0")
}
}
@@ -176,11 +176,11 @@ func BenchmarkActivationPeriodStoreRestore(b *testing.B) {
ap := &ActivationPeriod{ActivationTime: d}
ap.AddInterval(i)
- ap1 := ActivationPeriod{}
+ ap1 := &ActivationPeriod{}
b.StartTimer()
for i := 0; i < b.N; i++ {
- result, _ := Marshal(ap)
- Unmarshal(result, ap1)
+ result, _ := ap.Store()
+ ap1.Restore(result)
}
}
@@ -195,7 +195,7 @@ func BenchmarkActivationPeriodMarshallerMyStoreRestore(b *testing.B) {
ap := &ActivationPeriod{ActivationTime: d}
ap.AddInterval(i)
- ap1 := ActivationPeriod{}
+ ap1 := &ActivationPeriod{}
b.StartTimer()
ms := new(MyMarshaler)
for i := 0; i < b.N; i++ {
diff --git a/rater/dateseries.go b/rater/dateseries.go
index 167eb5b97..31d3f9538 100644
--- a/rater/dateseries.go
+++ b/rater/dateseries.go
@@ -73,23 +73,6 @@ func (ys *Years) Parse(input, sep string) {
}
}
-func (yss Years) store() (result string) {
- for _, ys := range yss {
- result += strconv.Itoa(int(ys)) + ","
- }
- result = strings.TrimRight(result, ",")
- return
-}
-
-func (yss *Years) restore(input string) {
- for _, ys := range strings.Split(input, ",") {
- if ys != "" {
- mm, _ := strconv.Atoi(ys)
- *yss = append(*yss, mm)
- }
- }
-}
-
// Defines months series
type Months []time.Month
@@ -138,23 +121,6 @@ func (m *Months) Parse(input, sep string) {
}
}
-func (ms Months) store() (result string) {
- for _, m := range ms {
- result += strconv.Itoa(int(m)) + ","
- }
- result = strings.TrimRight(result, ",")
- return
-}
-
-func (ms *Months) restore(input string) {
- for _, m := range strings.Split(input, ",") {
- if m != "" {
- mm, _ := strconv.Atoi(m)
- *ms = append(*ms, time.Month(mm))
- }
- }
-}
-
// Defines month days series
type MonthDays []int
@@ -203,23 +169,6 @@ func (md *MonthDays) Parse(input, sep string) {
}
}
-func (mds MonthDays) store() (result string) {
- for _, md := range mds {
- result += strconv.Itoa(int(md)) + ","
- }
- result = strings.TrimRight(result, ",")
- return
-}
-
-func (mds *MonthDays) restore(input string) {
- for _, md := range strings.Split(input, ",") {
- if md != "" {
- mm, _ := strconv.Atoi(md)
- *mds = append(*mds, mm)
- }
- }
-}
-
// Defines week days series
type WeekDays []time.Weekday
@@ -266,20 +215,3 @@ func (wd *WeekDays) Parse(input, sep string) {
}
}
}
-
-func (wds WeekDays) store() (result string) {
- for _, wd := range wds {
- result += strconv.Itoa(int(wd)) + ","
- }
- result = strings.TrimRight(result, ",")
- return
-}
-
-func (wds *WeekDays) restore(input string) {
- for _, wd := range strings.Split(input, ",") {
- if wd != "" {
- mm, _ := strconv.Atoi(wd)
- *wds = append(*wds, time.Weekday(mm))
- }
- }
-}
diff --git a/rater/dateseries_test.go b/rater/dateseries_test.go
index 830ef6043..401a5604e 100644
--- a/rater/dateseries_test.go
+++ b/rater/dateseries_test.go
@@ -25,58 +25,6 @@ import (
"time"
)
-func TestMonthYearStoreRestore(t *testing.T) {
- y := Years{2010, 2011, 2012}
- r := y.store()
- if string(r) != "2010,2011,2012" {
- t.Errorf("Error serializing years: %v", string(r))
- }
- o := Years{}
- o.restore(r)
- if !reflect.DeepEqual(o, y) {
- t.Errorf("Expected %v was %v", y, o)
- }
-}
-
-func TestMonthStoreRestore(t *testing.T) {
- m := Months{5, 6, 7, 8}
- r := m.store()
- if string(r) != "5,6,7,8" {
- t.Errorf("Error serializing months: %v", string(r))
- }
- o := Months{}
- o.restore(r)
- if !reflect.DeepEqual(o, m) {
- t.Errorf("Expected %v was %v", m, o)
- }
-}
-
-func TestMonthDayStoreRestore(t *testing.T) {
- md := MonthDays{24, 25, 26}
- r := md.store()
- if string(r) != "24,25,26" {
- t.Errorf("Error serializing month days: %v", string(r))
- }
- o := MonthDays{}
- o.restore(r)
- if !reflect.DeepEqual(o, md) {
- t.Errorf("Expected %v was %v", md, o)
- }
-}
-
-func TestWeekDayStoreRestore(t *testing.T) {
- wd := WeekDays{time.Saturday, time.Sunday}
- r := wd.store()
- if string(r) != "6,0" {
- t.Errorf("Error serializing week days: %v", string(r))
- }
- o := WeekDays{}
- o.restore(r)
- if !reflect.DeepEqual(o, wd) {
- t.Errorf("Expected %v was %v", wd, o)
- }
-}
-
func TestMonthStoreRestoreJson(t *testing.T) {
m := Months{5, 6, 7, 8}
r, _ := json.Marshal(m)
diff --git a/rater/destinations.go b/rater/destinations.go
index a841be14a..aa61a69f5 100644
--- a/rater/destinations.go
+++ b/rater/destinations.go
@@ -69,15 +69,3 @@ func (d *Destination) String() (result string) {
result = strings.TrimRight(result, ", ")
return result
}
-
-func (d *Destination) store() (result string) {
- for _, p := range d.Prefixes {
- result += p + ","
- }
- result = strings.TrimRight(result, ",")
- return
-}
-
-func (d *Destination) restore(input string) {
- d.Prefixes = strings.Split(input, ",")
-}
diff --git a/rater/interval.go b/rater/interval.go
index f72aaae47..05f2aa0ad 100644
--- a/rater/interval.go
+++ b/rater/interval.go
@@ -132,42 +132,3 @@ func (i *Interval) Equal(o *Interval) bool {
i.StartTime == o.StartTime &&
i.EndTime == o.EndTime
}
-
-/*
-Serializes the intervals for the storag. Used for key-value storages.
-*/
-func (i *Interval) store() (result string) {
- result += i.Years.store() + ";"
- result += i.Months.store() + ";"
- result += i.MonthDays.store() + ";"
- result += i.WeekDays.store() + ";"
- result += i.StartTime + ";"
- result += i.EndTime + ";"
- result += strconv.FormatFloat(i.Weight, 'f', -1, 64) + ";"
- result += strconv.FormatFloat(i.ConnectFee, 'f', -1, 64) + ";"
- result += strconv.FormatFloat(i.Price, 'f', -1, 64) + ";"
- result += strconv.FormatFloat(i.PricedUnits, 'f', -1, 64) + ";"
- result += strconv.FormatFloat(i.RateIncrements, 'f', -1, 64)
- return
-}
-
-/*
-De-serializes the interval for the storage. Used for key-value storages.
-*/
-func (i *Interval) restore(input string) {
- is := strings.Split(input, ";")
- if len(is) != 11 {
- return
- }
- i.Years.restore(is[0])
- i.Months.restore(is[1])
- i.MonthDays.restore(is[2])
- i.WeekDays.restore(is[3])
- i.StartTime = is[4]
- i.EndTime = is[5]
- i.Weight, _ = strconv.ParseFloat(is[6], 64)
- i.ConnectFee, _ = strconv.ParseFloat(is[7], 64)
- i.Price, _ = strconv.ParseFloat(is[8], 64)
- i.PricedUnits, _ = strconv.ParseFloat(is[9], 64)
- i.RateIncrements, _ = strconv.ParseFloat(is[10], 64)
-}
diff --git a/rater/interval_test.go b/rater/interval_test.go
index adb8efa90..58c71b193 100644
--- a/rater/interval_test.go
+++ b/rater/interval_test.go
@@ -19,44 +19,10 @@ along with this program. If not, see
package rater
import (
- "reflect"
"testing"
"time"
)
-func TestIntervalStoreRestore(t *testing.T) {
- i := &Interval{
- Months: 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},
- MonthDays: MonthDays{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},
- WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
- StartTime: "18:00:00",
- EndTime: "00:00:00",
- Weight: 10.0,
- ConnectFee: 0.0,
- Price: 1.0,
- PricedUnits: 60,
- RateIncrements: 1,
- }
- r := i.store()
- if string(r) != ";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" {
- t.Errorf("Error serializing interval: %v", string(r))
- }
- o := &Interval{}
- o.restore(r)
- if !reflect.DeepEqual(o, i) {
- t.Errorf("Expected %v was %v", i, o)
- }
-}
-
-func TestIntervalRestoreFromString(t *testing.T) {
- s := ";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,6,0;00:00:00;;10;0;0.2;60;1"
- i := Interval{}
- i.restore(s)
- if i.Price != 0.2 {
- t.Errorf("Error restoring inteval period from string %+v", i)
- }
-}
-
func TestIntervalMonth(t *testing.T) {
i := &Interval{Months: Months{time.February}}
d := time.Date(2012, time.February, 10, 23, 0, 0, 0, time.UTC)
diff --git a/rater/minute_buckets.go b/rater/minute_buckets.go
index 760739c9f..61bae4bcb 100644
--- a/rater/minute_buckets.go
+++ b/rater/minute_buckets.go
@@ -21,8 +21,6 @@ package rater
import (
"math"
"sort"
- "strconv"
- "strings"
)
type MinuteBucket struct {
@@ -84,29 +82,3 @@ func (bs bucketsorter) Less(j, i int) bool {
func (bs bucketsorter) Sort() {
sort.Sort(bs)
}
-
-/*
-Serializes the minute bucket for the storage. Used for key-value storages.
-*/
-func (mb *MinuteBucket) store() (result string) {
- result += strconv.FormatFloat(mb.Seconds, 'f', -1, 64) + ";"
- result += strconv.FormatFloat(mb.Weight, 'f', -1, 64) + ";"
- result += strconv.FormatFloat(mb.Price, 'f', -1, 64) + ";"
- result += strconv.FormatFloat(mb.Percent, 'f', -1, 64) + ";"
- result += mb.DestinationId
- return
-}
-
-/*
-De-serializes the minute bucket for the storage. Used for key-value storages.
-*/
-func (mb *MinuteBucket) restore(input string) {
- elements := strings.Split(input, ";")
- if len(elements) == 5 {
- mb.Seconds, _ = strconv.ParseFloat(elements[0], 64)
- mb.Weight, _ = strconv.ParseFloat(elements[1], 64)
- mb.Price, _ = strconv.ParseFloat(elements[2], 64)
- mb.Percent, _ = strconv.ParseFloat(elements[3], 64)
- mb.DestinationId = elements[4]
- }
-}
diff --git a/rater/simple_marshaller.go b/rater/simple_marshaller.go
deleted file mode 100644
index 604d88e99..000000000
--- a/rater/simple_marshaller.go
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-Rating system designed to be used in VoIP Carriers World
-Copyright (C) 2013 ITsysCOM
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-
-package rater
-
-import (
- "errors"
- "strconv"
- "strings"
- "time"
-)
-
-func Marshal(v interface{}) ([]byte, error) {
- switch i := v.(type) {
- case *ActivationPeriod:
- result, err := activationPeriodStore(i)
- return []byte(result), err
- case *RatingProfile:
- result, err := ratingProfileStore(i)
- return []byte(result), err
- }
- return nil, errors.New("Not supported type")
-}
-
-func Unmarshal(data []byte, v interface{}) error {
- switch i := v.(type) {
- case *ActivationPeriod:
- return activationPeriodRestore(string(data), i)
- case *RatingProfile:
- return ratingProfileRestore(string(data), i)
- }
- return errors.New("Not supported type")
-}
-
-func activationPeriodStore(ap *ActivationPeriod) (result string, err error) {
- result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + "|"
- for _, i := range ap.Intervals {
- result += i.store() + "|"
- }
- result = strings.TrimRight(result, "|")
- return
-}
-
-func activationPeriodRestore(input string, ap *ActivationPeriod) error {
- elements := strings.Split(input, "|")
- unixNano, _ := strconv.ParseInt(elements[0], 10, 64)
- ap.ActivationTime = time.Unix(0, unixNano).In(time.UTC)
- els := elements[1:]
- if len(els) > 1 {
- els = elements[1 : len(elements)-1]
- }
- for _, is := range els {
- i := &Interval{}
- i.restore(is)
- ap.Intervals = append(ap.Intervals, i)
- }
- return nil
-}
-
-func ratingProfileStore(rp *RatingProfile) (result string, err error) {
- result += rp.FallbackKey + ">"
- for k, aps := range rp.DestinationMap {
- result += k + "="
- for _, ap := range aps {
- aps, err := activationPeriodStore(ap)
- if err != nil {
- return result, err
- }
- result += aps + "<"
- }
- result = strings.TrimRight(result, "<")
- result += ">"
- }
- result = strings.TrimRight(result, ">")
- return
-}
-
-func ratingProfileRestore(input string, rp *RatingProfile) error {
- if rp.DestinationMap == nil {
- rp.DestinationMap = make(map[string][]*ActivationPeriod, 1)
- }
- elements := strings.Split(input, ">")
- rp.FallbackKey = elements[0]
- for _, kv := range elements[1:] {
- pair := strings.SplitN(kv, "=", 2)
- apList := strings.Split(pair[1], "<")
- var newAps []*ActivationPeriod
- for _, aps := range apList {
- ap := new(ActivationPeriod)
- err := activationPeriodRestore(aps, ap)
- if err != nil {
- return err
- }
- newAps = append(newAps, ap)
- }
- rp.DestinationMap[pair[0]] = newAps
- }
- return nil
-}
diff --git a/rater/simple_marshaller_test.go b/rater/simple_marshaller_test.go
deleted file mode 100644
index 129528afe..000000000
--- a/rater/simple_marshaller_test.go
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-Rating system designed to be used in VoIP Carriers World
-Copyright (C) 2013 ITsysCOM
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see
-*/
-
-package rater
-
-import (
- "reflect"
- "testing"
- "time"
-)
-
-func TestSimpleMarshallerApStoreRestore(t *testing.T) {
- d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC)
- i := &Interval{
- Months: Months{time.February},
- MonthDays: MonthDays{1},
- WeekDays: []time.Weekday{time.Wednesday, time.Thursday},
- StartTime: "14:30:00",
- EndTime: "15:00:00"}
- ap := &ActivationPeriod{ActivationTime: d}
- ap.AddInterval(i)
- result, err := Marshal(ap)
- expected := []byte("1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0")
- if err != nil || !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected %q was %q", expected, result)
- }
- ap1 := &ActivationPeriod{}
- err = Unmarshal(result, ap1)
- if err != nil || !reflect.DeepEqual(ap, ap1) {
- t.Errorf("Expected %v was %v: %v", ap, ap1, err)
- }
-}
-
-func TestSimpleMarshallerApRestoreFromString(t *testing.T) {
- s := []byte("1325376000000000000|;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,6,0;00:00:00;;10;0;0.2;60;1\n")
- ap := &ActivationPeriod{}
- err := Unmarshal(s, ap)
- if err != nil || len(ap.Intervals) != 1 {
- t.Error("Error restoring activation period from string", ap)
- }
-}
-
-func TestRpStoreRestore(t *testing.T) {
- d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC)
- i := &Interval{
- Months: Months{time.February},
- MonthDays: MonthDays{1},
- WeekDays: []time.Weekday{time.Wednesday, time.Thursday},
- StartTime: "14:30:00",
- EndTime: "15:00:00"}
- ap := &ActivationPeriod{ActivationTime: d}
- ap.AddInterval(i)
- rp := &RatingProfile{FallbackKey: "test"}
- rp.AddActivationPeriodIfNotPresent("0723", ap)
- result, err := Marshal(rp)
- expected := []byte("test>0723=1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0")
- if err != nil || !reflect.DeepEqual(result, expected) {
- t.Errorf("Expected %q was %q", expected, result)
- }
- rp1 := &RatingProfile{}
- err = Unmarshal(result, rp1)
- if err != nil || !reflect.DeepEqual(rp, rp1) {
- t.Errorf("Expected %v was %v", rp, rp1)
- }
-}
diff --git a/rater/simple_serializer.go b/rater/simple_serializer.go
new file mode 100644
index 000000000..c1139bfc8
--- /dev/null
+++ b/rater/simple_serializer.go
@@ -0,0 +1,550 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2013 ITsysCOM
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package rater
+
+import (
+ "errors"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type Serializer interface {
+ Store() (string, error)
+ Restore(string) error
+}
+
+var notEnoughElements = errors.New("Too few elements to restore")
+
+func (ap *ActivationPeriod) Store() (result string, err error) {
+ result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + "|"
+ for _, i := range ap.Intervals {
+ str, err := i.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + "|"
+ }
+ result = strings.TrimRight(result, "|")
+ return
+}
+
+func (ap *ActivationPeriod) Restore(input string) error {
+ elements := strings.Split(input, "|")
+ unixNano, _ := strconv.ParseInt(elements[0], 10, 64)
+ ap.ActivationTime = time.Unix(0, unixNano).In(time.UTC)
+ els := elements[1:]
+ if len(els) > 1 {
+ els = elements[1 : len(elements)-1]
+ }
+ for _, is := range els {
+ i := &Interval{}
+ if err := i.Restore(is); err != nil {
+ return err
+ }
+ ap.Intervals = append(ap.Intervals, i)
+ }
+ return nil
+}
+
+func (rp *RatingProfile) Store() (result string, err error) {
+ result += rp.FallbackKey + ">"
+ for k, aps := range rp.DestinationMap {
+ result += k + "="
+ for _, ap := range aps {
+ aps, err := ap.Store()
+ if err != nil {
+ return result, err
+ }
+ result += aps + "<"
+ }
+ result = strings.TrimRight(result, "<")
+ result += ">"
+ }
+ result = strings.TrimRight(result, ">")
+ return
+}
+
+func (rp *RatingProfile) Restore(input string) error {
+ if rp.DestinationMap == nil {
+ rp.DestinationMap = make(map[string][]*ActivationPeriod, 1)
+ }
+ elements := strings.Split(input, ">")
+ rp.FallbackKey = elements[0]
+ for _, kv := range elements[1:] {
+ pair := strings.SplitN(kv, "=", 2)
+ apList := strings.Split(pair[1], "<")
+ var newAps []*ActivationPeriod
+ for _, aps := range apList {
+ ap := new(ActivationPeriod)
+ err := ap.Restore(aps)
+ if err != nil {
+ return err
+ }
+ newAps = append(newAps, ap)
+ }
+ rp.DestinationMap[pair[0]] = newAps
+ }
+ return nil
+}
+
+func (a *Action) Store() (result string, err error) {
+ result += a.Id + "|"
+ result += a.ActionType + "|"
+ result += a.BalanceId + "|"
+ result += a.Direction + "|"
+ result += strconv.FormatFloat(a.Units, 'f', -1, 64) + "|"
+ result += strconv.FormatFloat(a.Weight, 'f', -1, 64)
+ if a.MinuteBucket != nil {
+ result += "|"
+ str, err := a.MinuteBucket.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str
+ }
+ return
+}
+
+func (a *Action) Restore(input string) error {
+ elements := strings.Split(input, "|")
+ if len(elements) < 6 {
+ return notEnoughElements
+ }
+ a.Id = elements[0]
+ a.ActionType = elements[1]
+ a.BalanceId = elements[2]
+ a.Direction = elements[3]
+ a.Units, _ = strconv.ParseFloat(elements[4], 64)
+ a.Weight, _ = strconv.ParseFloat(elements[5], 64)
+ if len(elements) == 7 {
+ a.MinuteBucket = &MinuteBucket{}
+ if err := a.MinuteBucket.Restore(elements[6]); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (as Actions) Store() (result string, err error) {
+ for _, a := range as {
+ str, err := a.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + "~"
+ }
+ result = strings.TrimRight(result, "~")
+ return
+}
+
+func (as *Actions) Restore(input string) error {
+ for _, a_string := range strings.Split(input, "~") {
+ if len(a_string) > 0 {
+ a := &Action{}
+ if err := a.Restore(a_string); err != nil {
+ return err
+ }
+ *as = append(*as, a)
+ }
+ }
+ return nil
+}
+
+func (at *ActionTiming) Store() (result string, err error) {
+ result += at.Id + "|"
+ result += at.Tag + "|"
+ for _, ubi := range at.UserBalanceIds {
+ result += ubi + ","
+ }
+ result = strings.TrimRight(result, ",") + "|"
+ if at.Timing != nil {
+ str, err := at.Timing.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + "|"
+ } else {
+ result += " |"
+ }
+ result += strconv.FormatFloat(at.Weight, 'f', -1, 64) + "|"
+ result += at.ActionsId
+ return
+}
+
+func (at *ActionTiming) Restore(input string) error {
+ elements := strings.Split(input, "|")
+ at.Id = elements[0]
+ at.Tag = elements[1]
+ for _, ubi := range strings.Split(elements[2], ",") {
+ if strings.TrimSpace(ubi) != "" {
+ at.UserBalanceIds = append(at.UserBalanceIds, ubi)
+ }
+ }
+
+ at.Timing = &Interval{}
+ if err := at.Timing.Restore(elements[3]); err != nil {
+ return err
+ }
+ at.Weight, _ = strconv.ParseFloat(elements[4], 64)
+ at.ActionsId = elements[5]
+ return nil
+}
+
+func (ats ActionTimings) Store() (result string, err error) {
+ for _, at := range ats {
+ str, err := at.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + "~"
+ }
+ result = strings.TrimRight(result, "~")
+ return
+}
+
+func (ats *ActionTimings) Restore(input string) error {
+ for _, at_string := range strings.Split(input, "~") {
+ if len(at_string) > 0 {
+ at := &ActionTiming{}
+ if err := at.Restore(at_string); err != nil {
+ return err
+ }
+ *ats = append(*ats, at)
+ }
+ }
+ return nil
+}
+
+func (at *ActionTrigger) Store() (result string, err error) {
+ result += at.Id + ";"
+ result += at.BalanceId + ";"
+ result += at.Direction + ";"
+ result += at.DestinationId + ";"
+ result += at.ActionsId + ";"
+ result += strconv.FormatFloat(at.ThresholdValue, 'f', -1, 64) + ";"
+ result += strconv.FormatFloat(at.Weight, 'f', -1, 64) + ";"
+ result += strconv.FormatBool(at.Executed)
+ return
+}
+
+func (at *ActionTrigger) Restore(input string) error {
+ elements := strings.Split(input, ";")
+ if len(elements) != 8 {
+ return notEnoughElements
+ }
+ at.Id = elements[0]
+ at.BalanceId = elements[1]
+ at.Direction = elements[2]
+ at.DestinationId = elements[3]
+ at.ActionsId = elements[4]
+ at.ThresholdValue, _ = strconv.ParseFloat(elements[5], 64)
+ at.Weight, _ = strconv.ParseFloat(elements[6], 64)
+ at.Executed, _ = strconv.ParseBool(elements[7])
+ return nil
+}
+
+func (ub *UserBalance) Store() (result string, err error) {
+ result += ub.Id + "|"
+ result += ub.Type + "|"
+ for k, v := range ub.BalanceMap {
+ result += k + ":" + strconv.FormatFloat(v, 'f', -1, 64) + "#"
+ }
+ result = strings.TrimRight(result, "#") + "|"
+ for _, mb := range ub.MinuteBuckets {
+ str, err := mb.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + "#"
+ }
+ result = strings.TrimRight(result, "#") + "|"
+ for _, uc := range ub.UnitCounters {
+ str, err := uc.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + "#"
+ }
+ result = strings.TrimRight(result, "#") + "|"
+ for _, at := range ub.ActionTriggers {
+ res, err := at.Store()
+ if err != nil {
+ return "", err
+ }
+ result += res + "#"
+ }
+ result = strings.TrimRight(result, "#")
+ return
+}
+
+func (ub *UserBalance) Restore(input string) error {
+ elements := strings.Split(input, "|")
+ if len(elements) < 2 {
+ return notEnoughElements
+ }
+ ub.Id = elements[0]
+ ub.Type = elements[1]
+ if ub.BalanceMap == nil {
+ ub.BalanceMap = make(map[string]float64, 0)
+ }
+ for _, maps := range strings.Split(elements[2], "#") {
+ kv := strings.Split(maps, ":")
+ if len(kv) != 2 {
+ continue
+ }
+ value, _ := strconv.ParseFloat(kv[1], 64)
+ ub.BalanceMap[kv[0]] = value
+ }
+ for _, mbs := range strings.Split(elements[3], "#") {
+ if mbs == "" {
+ continue
+ }
+ mb := &MinuteBucket{}
+ if err := mb.Restore(mbs); err != nil {
+ return err
+ }
+ ub.MinuteBuckets = append(ub.MinuteBuckets, mb)
+ }
+ for _, ucs := range strings.Split(elements[4], "#") {
+ if ucs == "" {
+ continue
+ }
+ uc := &UnitsCounter{}
+ if err := uc.Restore(ucs); err != nil {
+ return err
+ }
+ ub.UnitCounters = append(ub.UnitCounters, uc)
+ }
+ for _, ats := range strings.Split(elements[5], "#") {
+ if ats == "" {
+ continue
+ }
+ at := &ActionTrigger{}
+ if err := at.Restore(ats); err != nil {
+ return err
+ }
+ ub.ActionTriggers = append(ub.ActionTriggers, at)
+ }
+ return nil
+}
+
+/*
+Serializes the unit counter for the storage. Used for key-value storages.
+*/
+func (uc *UnitsCounter) Store() (result string, err error) {
+ result += uc.Direction + "/"
+ result += uc.BalanceId + "/"
+ result += strconv.FormatFloat(uc.Units, 'f', -1, 64) + "/"
+ for _, mb := range uc.MinuteBuckets {
+ str, err := mb.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + ","
+ }
+ result = strings.TrimRight(result, ",")
+ return
+}
+
+/*
+De-serializes the unit counter for the storage. Used for key-value storages.
+*/
+func (uc *UnitsCounter) Restore(input string) error {
+ elements := strings.Split(input, "/")
+ if len(elements) != 4 {
+ return notEnoughElements
+ }
+ uc.Direction = elements[0]
+ uc.BalanceId = elements[1]
+ uc.Units, _ = strconv.ParseFloat(elements[2], 64)
+ for _, mbs := range strings.Split(elements[3], ",") {
+ mb := &MinuteBucket{}
+ if err := mb.Restore(mbs); err != nil {
+ return err
+ }
+ uc.MinuteBuckets = append(uc.MinuteBuckets, mb)
+ }
+ return nil
+}
+
+func (d *Destination) Store() (result string, err error) {
+ for _, p := range d.Prefixes {
+ result += p + ","
+ }
+ result = strings.TrimRight(result, ",")
+ return
+}
+
+func (d *Destination) Restore(input string) error {
+ d.Prefixes = strings.Split(input, ",")
+ return nil
+}
+
+func (i *Interval) Store() (result string, err error) {
+ str, err := i.Years.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + ";"
+ str, err = i.Months.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + ";"
+ str, err = i.MonthDays.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + ";"
+ str, err = i.WeekDays.Store()
+ if err != nil {
+ return "", err
+ }
+ result += str + ";"
+ result += i.StartTime + ";"
+ result += i.EndTime + ";"
+ result += strconv.FormatFloat(i.Weight, 'f', -1, 64) + ";"
+ result += strconv.FormatFloat(i.ConnectFee, 'f', -1, 64) + ";"
+ result += strconv.FormatFloat(i.Price, 'f', -1, 64) + ";"
+ result += strconv.FormatFloat(i.PricedUnits, 'f', -1, 64) + ";"
+ result += strconv.FormatFloat(i.RateIncrements, 'f', -1, 64)
+ return
+}
+
+func (i *Interval) Restore(input string) error {
+ is := strings.Split(input, ";")
+ if len(is) != 11 {
+ return notEnoughElements
+ }
+ if err := i.Years.Restore(is[0]); err != nil {
+ return err
+ }
+ if err := i.Months.Restore(is[1]); err != nil {
+ return err
+ }
+ if err := i.MonthDays.Restore(is[2]); err != nil {
+ return err
+ }
+ if err := i.WeekDays.Restore(is[3]); err != nil {
+ return err
+ }
+ i.StartTime = is[4]
+ i.EndTime = is[5]
+ i.Weight, _ = strconv.ParseFloat(is[6], 64)
+ i.ConnectFee, _ = strconv.ParseFloat(is[7], 64)
+ i.Price, _ = strconv.ParseFloat(is[8], 64)
+ i.PricedUnits, _ = strconv.ParseFloat(is[9], 64)
+ i.RateIncrements, _ = strconv.ParseFloat(is[10], 64)
+ return nil
+}
+
+func (mb *MinuteBucket) Store() (result string, err error) {
+ result += strconv.FormatFloat(mb.Seconds, 'f', -1, 64) + ";"
+ result += strconv.FormatFloat(mb.Weight, 'f', -1, 64) + ";"
+ result += strconv.FormatFloat(mb.Price, 'f', -1, 64) + ";"
+ result += strconv.FormatFloat(mb.Percent, 'f', -1, 64) + ";"
+ result += mb.DestinationId
+ return
+}
+
+func (mb *MinuteBucket) Restore(input string) error {
+ elements := strings.Split(input, ";")
+ if len(elements) == 5 {
+ mb.Seconds, _ = strconv.ParseFloat(elements[0], 64)
+ mb.Weight, _ = strconv.ParseFloat(elements[1], 64)
+ mb.Price, _ = strconv.ParseFloat(elements[2], 64)
+ mb.Percent, _ = strconv.ParseFloat(elements[3], 64)
+ mb.DestinationId = elements[4]
+ return nil
+ }
+ return notEnoughElements
+}
+
+func (wds WeekDays) Store() (result string, err error) {
+ for _, wd := range wds {
+ result += strconv.Itoa(int(wd)) + ","
+ }
+ result = strings.TrimRight(result, ",")
+ return
+}
+
+func (wds *WeekDays) Restore(input string) error {
+ for _, wd := range strings.Split(input, ",") {
+ if wd != "" {
+ mm, _ := strconv.Atoi(wd)
+ *wds = append(*wds, time.Weekday(mm))
+ }
+ }
+ return nil
+}
+
+func (mds MonthDays) Store() (result string, err error) {
+ for _, md := range mds {
+ result += strconv.Itoa(int(md)) + ","
+ }
+ result = strings.TrimRight(result, ",")
+ return
+}
+
+func (mds *MonthDays) Restore(input string) error {
+ for _, md := range strings.Split(input, ",") {
+ if md != "" {
+ mm, _ := strconv.Atoi(md)
+ *mds = append(*mds, mm)
+ }
+ }
+ return nil
+}
+
+func (ms Months) Store() (result string, err error) {
+ for _, m := range ms {
+ result += strconv.Itoa(int(m)) + ","
+ }
+ result = strings.TrimRight(result, ",")
+ return
+}
+
+func (ms *Months) Restore(input string) error {
+ for _, m := range strings.Split(input, ",") {
+ if m != "" {
+ mm, _ := strconv.Atoi(m)
+ *ms = append(*ms, time.Month(mm))
+ }
+ }
+ return nil
+}
+
+func (yss Years) Store() (result string, err error) {
+ for _, ys := range yss {
+ result += strconv.Itoa(int(ys)) + ","
+ }
+ result = strings.TrimRight(result, ",")
+ return
+}
+
+func (yss *Years) Restore(input string) error {
+ for _, ys := range strings.Split(input, ",") {
+ if ys != "" {
+ mm, _ := strconv.Atoi(ys)
+ *yss = append(*yss, mm)
+ }
+ }
+ return nil
+}
diff --git a/rater/simple_serializer_test.go b/rater/simple_serializer_test.go
new file mode 100644
index 000000000..1ca0f3229
--- /dev/null
+++ b/rater/simple_serializer_test.go
@@ -0,0 +1,218 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2013 ITsysCOM
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package rater
+
+import (
+ "reflect"
+ "testing"
+ "time"
+)
+
+func TestSimpleMarshallerApStoreRestore(t *testing.T) {
+ d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC)
+ i := &Interval{
+ Months: Months{time.February},
+ MonthDays: MonthDays{1},
+ WeekDays: []time.Weekday{time.Wednesday, time.Thursday},
+ StartTime: "14:30:00",
+ EndTime: "15:00:00"}
+ ap := &ActivationPeriod{ActivationTime: d}
+ ap.AddInterval(i)
+ result, err := ap.Store()
+ expected := "1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0"
+ if err != nil || !reflect.DeepEqual(result, expected) {
+ t.Errorf("Expected %q was %q", expected, result)
+ }
+ ap1 := &ActivationPeriod{}
+ err = ap1.Restore(result)
+ if err != nil || !reflect.DeepEqual(ap, ap1) {
+ t.Errorf("Expected %v was %v: %v", ap, ap1, err)
+ }
+}
+
+func TestSimpleMarshallerApRestoreFromString(t *testing.T) {
+ s := "1325376000000000000|;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,6,0;00:00:00;;10;0;0.2;60;1\n"
+ ap := &ActivationPeriod{}
+ err := ap.Restore(s)
+ if err != nil || len(ap.Intervals) != 1 {
+ t.Error("Error restoring activation period from string", ap)
+ }
+}
+
+func TestRpStoreRestore(t *testing.T) {
+ d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC)
+ i := &Interval{
+ Months: Months{time.February},
+ MonthDays: MonthDays{1},
+ WeekDays: []time.Weekday{time.Wednesday, time.Thursday},
+ StartTime: "14:30:00",
+ EndTime: "15:00:00"}
+ ap := &ActivationPeriod{ActivationTime: d}
+ ap.AddInterval(i)
+ rp := &RatingProfile{FallbackKey: "test"}
+ rp.AddActivationPeriodIfNotPresent("0723", ap)
+ result, err := rp.Store()
+ expected := "test>0723=1328106601000000000|;2;1;3,4;14:30:00;15:00:00;0;0;0;0;0"
+ if err != nil || !reflect.DeepEqual(result, expected) {
+ t.Errorf("Expected %q was %q", expected, result)
+ }
+ rp1 := &RatingProfile{}
+ err = rp1.Restore(result)
+ if err != nil || !reflect.DeepEqual(rp, rp1) {
+ t.Errorf("Expected %v was %v", rp, rp1)
+ }
+}
+
+func TestActionTimingStoreRestore(t *testing.T) {
+ i := &Interval{
+ Months: 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},
+ MonthDays: MonthDays{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},
+ WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
+ StartTime: "18:00:00",
+ EndTime: "00:00:00",
+ Weight: 10.0,
+ ConnectFee: 0.0,
+ Price: 1.0,
+ PricedUnits: 60,
+ RateIncrements: 1,
+ }
+ at := &ActionTiming{
+ Id: "some uuid",
+ Tag: "test",
+ UserBalanceIds: []string{"one", "two", "three"},
+ Timing: i,
+ Weight: 10.0,
+ ActionsId: "Commando",
+ }
+ r, err := at.Store()
+ if err != nil || r != "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|Commando" {
+ t.Errorf("Error serializing action timing: %v", string(r))
+ }
+ o := &ActionTiming{}
+ err = o.Restore(r)
+ if err != nil || !reflect.DeepEqual(o, at) {
+ t.Errorf("Expected %v was %v", at, o)
+ }
+}
+
+func TestActionTriggerStoreRestore(t *testing.T) {
+ at := &ActionTrigger{
+ Id: "some_uuid",
+ BalanceId: CREDIT,
+ Direction: OUTBOUND,
+ ThresholdValue: 100.0,
+ DestinationId: "NAT",
+ Weight: 10.0,
+ ActionsId: "Commando",
+ }
+ r, err := at.Store()
+ if err != nil || r != "some_uuid;MONETARY;OUT;NAT;Commando;100;10;false" {
+ t.Errorf("Error serializing action trigger: %v", string(r))
+ }
+ o := &ActionTrigger{}
+ err = o.Restore(r)
+ if err != nil || !reflect.DeepEqual(o, at) {
+ t.Errorf("Expected %v was %v", at, o)
+ }
+}
+
+func TestIntervalStoreRestore(t *testing.T) {
+ i := &Interval{
+ Months: 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},
+ MonthDays: MonthDays{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},
+ WeekDays: WeekDays{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday},
+ StartTime: "18:00:00",
+ EndTime: "00:00:00",
+ Weight: 10.0,
+ ConnectFee: 0.0,
+ Price: 1.0,
+ PricedUnits: 60,
+ RateIncrements: 1,
+ }
+ r, err := i.Store()
+ if err != nil || r != ";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" {
+ t.Errorf("Error serializing interval: %v", string(r))
+ }
+ o := &Interval{}
+ err = o.Restore(r)
+ if err != nil || !reflect.DeepEqual(o, i) {
+ t.Errorf("Expected %v was %v", i, o)
+ }
+}
+
+func TestIntervalRestoreFromString(t *testing.T) {
+ s := ";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,6,0;00:00:00;;10;0;0.2;60;1"
+ i := Interval{}
+ err := i.Restore(s)
+ if err != nil || i.Price != 0.2 {
+ t.Errorf("Error restoring inteval period from string %+v", i)
+ }
+}
+
+func TestMonthYearStoreRestore(t *testing.T) {
+ y := Years{2010, 2011, 2012}
+ r, err := y.Store()
+ if err != nil || r != "2010,2011,2012" {
+ t.Errorf("Error serializing years: %v", string(r))
+ }
+ o := Years{}
+ err = o.Restore(r)
+ if err != nil || !reflect.DeepEqual(o, y) {
+ t.Errorf("Expected %v was %v", y, o)
+ }
+}
+
+func TestMonthStoreRestore(t *testing.T) {
+ m := Months{5, 6, 7, 8}
+ r, err := m.Store()
+ if err != nil || r != "5,6,7,8" {
+ t.Errorf("Error serializing months: %v", string(r))
+ }
+ o := Months{}
+ err = o.Restore(r)
+ if err != nil || !reflect.DeepEqual(o, m) {
+ t.Errorf("Expected %v was %v", m, o)
+ }
+}
+
+func TestMonthDayStoreRestore(t *testing.T) {
+ md := MonthDays{24, 25, 26}
+ r, err := md.Store()
+ if err != nil || r != "24,25,26" {
+ t.Errorf("Error serializing month days: %v", string(r))
+ }
+ o := MonthDays{}
+ err = o.Restore(r)
+ if err != nil || !reflect.DeepEqual(o, md) {
+ t.Errorf("Expected %v was %v", md, o)
+ }
+}
+
+func TestWeekDayStoreRestore(t *testing.T) {
+ wd := WeekDays{time.Saturday, time.Sunday}
+ r, err := wd.Store()
+ if err != nil || r != "6,0" {
+ t.Errorf("Error serializing week days: %v", string(r))
+ }
+ o := WeekDays{}
+ err = o.Restore(r)
+ if err != nil || !reflect.DeepEqual(o, wd) {
+ t.Errorf("Expected %v was %v", wd, o)
+ }
+}
diff --git a/rater/storage_interface.go b/rater/storage_interface.go
index 876b65a2d..16b811d7b 100644
--- a/rater/storage_interface.go
+++ b/rater/storage_interface.go
@@ -25,7 +25,6 @@ import (
gmsgpack "github.com/ugorji/go-msgpack"
"github.com/vmihailenco/msgpack"
"labix.org/v2/mgo/bson"
- "strings"
)
const (
@@ -145,71 +144,15 @@ func (gm *GOBMarshaler) Unmarshal(data []byte, v interface{}) error {
return gob.NewDecoder(bytes.NewBuffer(data)).Decode(v)
}
-type storer interface {
- store() string
- restore(string)
+type MyMarshaler struct{}
+
+func (mm *MyMarshaler) Marshal(v interface{}) ([]byte, error) {
+ ser := v.(Serializer)
+ res, err := ser.Store()
+ return []byte(res), err
}
-type MyMarshaler struct {
- buf bytes.Buffer
-}
-
-func (mm *MyMarshaler) Marshal(v interface{}) (data []byte, err error) {
- switch v.(type) {
- case []*Action:
- result := ""
- for _, a := range v.([]*Action) {
- result += a.store() + "~"
- }
- result = strings.TrimRight(result, "~")
- return []byte(result), nil
- case []*ActionTiming:
- result := ""
- for _, at := range v.([]*ActionTiming) {
- result += at.store() + "~"
- }
- result = strings.TrimRight(result, "~")
- return []byte(result), nil
- case storer:
- s := v.(storer)
- return []byte(s.store()), nil
- }
- mm.buf.Reset()
- if err = json.NewEncoder(&mm.buf).Encode(v); err == nil {
- data = mm.buf.Bytes()
- }
- return
-}
-
-func (mm *MyMarshaler) Unmarshal(data []byte, v interface{}) (err error) {
- switch v.(type) {
- case *[]*Action:
- as := v.(*[]*Action)
- for _, a_string := range strings.Split(string(data), "~") {
- if len(a_string) > 0 {
- a := &Action{}
- a.restore(a_string)
- *as = append(*as, a)
- }
- }
- return nil
- case *[]*ActionTiming:
- ats := v.(*[]*ActionTiming)
- for _, at_string := range strings.Split(string(data), "~") {
- if len(at_string) > 0 {
- at := &ActionTiming{}
- at.restore(at_string)
- *ats = append(*ats, at)
- }
- }
- return nil
- case storer:
- s := v.(storer)
- s.restore(string(data))
- return nil
-
- }
- mm.buf.Reset()
- mm.buf.Write(data)
- return json.NewDecoder(&mm.buf).Decode(v)
+func (mm *MyMarshaler) Unmarshal(data []byte, v interface{}) error {
+ ser := v.(Serializer)
+ return ser.Restore(string(data))
}
diff --git a/rater/units_counter.go b/rater/units_counter.go
index db05d504b..ae59202bf 100644
--- a/rater/units_counter.go
+++ b/rater/units_counter.go
@@ -20,8 +20,6 @@ package rater
import (
"fmt"
- "strconv"
- "strings"
)
// Amount of a trafic of a certain type
@@ -67,35 +65,3 @@ func (uc *UnitsCounter) addMinutes(amount float64, prefix string) {
func (uc *UnitsCounter) String() string {
return fmt.Sprintf("%s %s %v", uc.BalanceId, uc.Direction, uc.Units)
}
-
-/*
-Serializes the unit counter for the storage. Used for key-value storages.
-*/
-func (uc *UnitsCounter) store() (result string) {
- result += uc.Direction + "/"
- result += uc.BalanceId + "/"
- result += strconv.FormatFloat(uc.Units, 'f', -1, 64) + "/"
- for _, mb := range uc.MinuteBuckets {
- result += mb.store() + ","
- }
- result = strings.TrimRight(result, ",")
- return
-}
-
-/*
-De-serializes the unit counter for the storage. Used for key-value storages.
-*/
-func (uc *UnitsCounter) restore(input string) {
- elements := strings.Split(input, "/")
- if len(elements) != 4 {
- return
- }
- uc.Direction = elements[0]
- uc.BalanceId = elements[1]
- uc.Units, _ = strconv.ParseFloat(elements[2], 64)
- for _, mbs := range strings.Split(elements[3], ",") {
- mb := &MinuteBucket{}
- mb.restore(mbs)
- uc.MinuteBuckets = append(uc.MinuteBuckets, mb)
- }
-}
diff --git a/rater/units_counter_test.go b/rater/units_counter_test.go
index 32958dc83..059a2866b 100644
--- a/rater/units_counter_test.go
+++ b/rater/units_counter_test.go
@@ -30,13 +30,13 @@ func TestUnitsCounterStoreRestore(t *testing.T) {
Units: 100,
MinuteBuckets: []*MinuteBucket{&MinuteBucket{Weight: 20, Price: 1, DestinationId: "NAT"}, &MinuteBucket{Weight: 10, Price: 10, Percent: 0, DestinationId: "RET"}},
}
- r := uc.store()
- if string(r) != "OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET" {
+ r, err := uc.Store()
+ if err != nil || r != "OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET" {
t.Errorf("Error serializing units counter: %v", string(r))
}
o := &UnitsCounter{}
- o.restore(r)
- if !reflect.DeepEqual(o, uc) {
+ err = o.Restore(r)
+ if err != nil || !reflect.DeepEqual(o, uc) {
t.Errorf("Expected %v was %v", uc, o)
}
}
diff --git a/rater/userbalance.go b/rater/userbalance.go
index 18b49cebd..332d8360a 100644
--- a/rater/userbalance.go
+++ b/rater/userbalance.go
@@ -21,8 +21,6 @@ package rater
import (
"errors"
//"log"
- "strconv"
- "strings"
)
const (
@@ -274,75 +272,3 @@ func (ub *UserBalance) initMinuteCounters() {
}
}
}
-
-/*
-Serializes the user balance for the storage. Used for key-value storages.
-*/
-func (ub *UserBalance) store() (result string) {
- result += ub.Id + "|"
- result += ub.Type + "|"
- for k, v := range ub.BalanceMap {
- result += k + ":" + strconv.FormatFloat(v, 'f', -1, 64) + "#"
- }
- result = strings.TrimRight(result, "#") + "|"
- for _, mb := range ub.MinuteBuckets {
- result += mb.store() + "#"
- }
- result = strings.TrimRight(result, "#") + "|"
- for _, uc := range ub.UnitCounters {
- result += uc.store() + "#"
- }
- result = strings.TrimRight(result, "#") + "|"
- for _, at := range ub.ActionTriggers {
- result += at.store() + "#"
- }
- result = strings.TrimRight(result, "#")
- return
-}
-
-/*
-De-serializes the user balance for the storage. Used for key-value storages.
-*/
-func (ub *UserBalance) restore(input string) {
- elements := strings.Split(input, "|")
- if len(elements) < 2 {
- return
- }
- ub.Id = elements[0]
- ub.Type = elements[1]
- if ub.BalanceMap == nil {
- ub.BalanceMap = make(map[string]float64, 0)
- }
- for _, maps := range strings.Split(elements[2], "#") {
- kv := strings.Split(maps, ":")
- if len(kv) != 2 {
- continue
- }
- value, _ := strconv.ParseFloat(kv[1], 64)
- ub.BalanceMap[kv[0]] = value
- }
- for _, mbs := range strings.Split(elements[3], "#") {
- if mbs == "" {
- continue
- }
- mb := &MinuteBucket{}
- mb.restore(mbs)
- ub.MinuteBuckets = append(ub.MinuteBuckets, mb)
- }
- for _, ucs := range strings.Split(elements[4], "#") {
- if ucs == "" {
- continue
- }
- uc := &UnitsCounter{}
- uc.restore(ucs)
- ub.UnitCounters = append(ub.UnitCounters, uc)
- }
- for _, ats := range strings.Split(elements[5], "#") {
- if ats == "" {
- continue
- }
- at := &ActionTrigger{}
- at.restore(ats)
- ub.ActionTriggers = append(ub.ActionTriggers, at)
- }
-}
diff --git a/rater/userbalance_test.go b/rater/userbalance_test.go
index 23b036a0f..cbfe1a25b 100644
--- a/rater/userbalance_test.go
+++ b/rater/userbalance_test.go
@@ -70,14 +70,14 @@ func TestUserBalanceStoreRestore(t *testing.T) {
UnitCounters: []*UnitsCounter{uc, uc},
ActionTriggers: ActionTriggerPriotityList{at, at, at},
}
- r := ub.store()
- if string(r) != "rif|postpaid|SMSOUT:14#INTERNETOUT:1024|0;20;1;0;NAT#0;10;10;0;RET|OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET#OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET|some_uuid;MONETARY;OUT;NAT;Commando;100;10;false#some_uuid;MONETARY;OUT;NAT;Commando;100;10;false#some_uuid;MONETARY;OUT;NAT;Commando;100;10;false" &&
- string(r) != "rif|postpaid|INTERNETOUT:1024#SMSOUT:14|0;20;1;0;NAT#0;10;10;0;RET|OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET#OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET|some_uuid;MONETARY;OUT;NAT;Commando;100;10;false#some_uuid;MONETARY;OUT;NAT;Commando;100;10;false#some_uuid;MONETARY;OUT;NAT;Commando;100;10;false" {
+ r, err := ub.Store()
+ if err != nil || r != "rif|postpaid|SMSOUT:14#INTERNETOUT:1024|0;20;1;0;NAT#0;10;10;0;RET|OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET#OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET|some_uuid;MONETARY;OUT;NAT;Commando;100;10;false#some_uuid;MONETARY;OUT;NAT;Commando;100;10;false#some_uuid;MONETARY;OUT;NAT;Commando;100;10;false" &&
+ r != "rif|postpaid|INTERNETOUT:1024#SMSOUT:14|0;20;1;0;NAT#0;10;10;0;RET|OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET#OUT/SMS/100/0;20;1;0;NAT,0;10;10;0;RET|some_uuid;MONETARY;OUT;NAT;Commando;100;10;false#some_uuid;MONETARY;OUT;NAT;Commando;100;10;false#some_uuid;MONETARY;OUT;NAT;Commando;100;10;false" {
t.Errorf("Error serializing action timing: %v", string(r))
}
o := &UserBalance{}
- o.restore(r)
- if !reflect.DeepEqual(o, ub) {
+ err = o.Restore(r)
+ if err != nil || !reflect.DeepEqual(o, ub) {
t.Errorf("Expected %v was %v", ub, o)
}
}