mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
switched to json encoding, removed mongo and kyoto and started actions importing
This commit is contained in:
@@ -25,14 +25,16 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
primaryBalanceActions []*timespans.Action
|
||||
destinatioBalanceActions []*timespans.Action
|
||||
actions = make(map[string][]*timespans.Action)
|
||||
actionsTimings []*timespans.Action
|
||||
actionsTriggers []*timespans.Action
|
||||
accountActions []*timespans.Action
|
||||
)
|
||||
|
||||
func loadPrimaryBalanceActions() {
|
||||
fp, err := os.Open(*primaryBalanceActionsFn)
|
||||
func loadActions() {
|
||||
fp, err := os.Open(*actionsFn)
|
||||
if err != nil {
|
||||
log.Printf("Could not open primary balance actions file: %v", err)
|
||||
log.Printf("Could not open actions file: %v", err)
|
||||
return
|
||||
}
|
||||
defer fp.Close()
|
||||
@@ -45,12 +47,32 @@ func loadPrimaryBalanceActions() {
|
||||
continue
|
||||
}
|
||||
//primaryBalanceActions = append(primaryBalanceActions, record[1:]...)
|
||||
log.Print(tag, primaryBalanceActions)
|
||||
log.Print(tag, actions)
|
||||
}
|
||||
}
|
||||
|
||||
func loadDestinationBalanceActions() {
|
||||
fp, err := os.Open(*destinationBalanceActionsFn)
|
||||
func loadActionsTimings() {
|
||||
fp, err := os.Open(*actionstimingsFn)
|
||||
if err != nil {
|
||||
log.Printf("Could not open actions timings file: %v", err)
|
||||
return
|
||||
}
|
||||
defer fp.Close()
|
||||
csvReader := csv.NewReader(fp)
|
||||
csvReader.Comma = sep
|
||||
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
|
||||
tag := record[0]
|
||||
if tag == "Tag" {
|
||||
// skip header line
|
||||
continue
|
||||
}
|
||||
//destinatioBalanceActions = append(destinatioBalanceActions, record[1:]...)
|
||||
log.Print(tag, actionsTimings)
|
||||
}
|
||||
}
|
||||
|
||||
func loadActionsTriggers() {
|
||||
fp, err := os.Open(*actionstriggersFn)
|
||||
if err != nil {
|
||||
log.Printf("Could not open destination balance actions file: %v", err)
|
||||
return
|
||||
@@ -65,6 +87,26 @@ func loadDestinationBalanceActions() {
|
||||
continue
|
||||
}
|
||||
//destinatioBalanceActions = append(destinatioBalanceActions, record[1:]...)
|
||||
log.Print(tag, destinatioBalanceActions)
|
||||
log.Print(tag, actionsTriggers)
|
||||
}
|
||||
}
|
||||
|
||||
func loadAccountActions() {
|
||||
fp, err := os.Open(*accountactionsFn)
|
||||
if err != nil {
|
||||
log.Printf("Could not open account actions file: %v", err)
|
||||
return
|
||||
}
|
||||
defer fp.Close()
|
||||
csvReader := csv.NewReader(fp)
|
||||
csvReader.Comma = sep
|
||||
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
|
||||
tag := record[0]
|
||||
if tag == "Tag" {
|
||||
// skip header line
|
||||
continue
|
||||
}
|
||||
//destinatioBalanceActions = append(destinatioBalanceActions, record[1:]...)
|
||||
log.Print(tag, accountActions)
|
||||
}
|
||||
}
|
||||
@@ -24,22 +24,24 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
separator = flag.String("separator", ",", "Default field separator")
|
||||
redisserver = flag.String("redisserver", "tcp:127.0.0.1:6379", "redis server address (tcp:127.0.0.1:6379)")
|
||||
redisdb = flag.Int("rdb", 10, "redis database number (10)")
|
||||
redispass = flag.String("pass", "", "redis database password")
|
||||
flush = flag.Bool("flush", false, "Flush the database before importing")
|
||||
monthsFn = flag.String("month", "Months.csv", "Months file")
|
||||
monthdaysFn = flag.String("monthdays", "MonthDays.csv", "Month days file")
|
||||
weekdaysFn = flag.String("weekdays", "WeekDays.csv", "Week days file")
|
||||
destinationsFn = flag.String("destinations", "Destinations.csv", "Destinations file")
|
||||
ratesFn = flag.String("rates", "Rates.csv", "Rates file")
|
||||
timingsFn = flag.String("timings", "Timings.csv", "Timings file")
|
||||
ratestimingsFn = flag.String("ratestimings", "RatesTimings.csv", "Rates timings file")
|
||||
ratingprofilesFn = flag.String("ratingprofiles", "RatingProfiles.csv", "Rating profiles file")
|
||||
primaryBalanceActionsFn = flag.String("primaryBalanceActions", "PrimaryBalanceActions.csv", "Primary balance actions file")
|
||||
destinationBalanceActionsFn = flag.String("destinationBalanceActions", "DestinationBalanceActions.csv", "Destination balance actions file")
|
||||
sep rune
|
||||
separator = flag.String("separator", ",", "Default field separator")
|
||||
redisserver = flag.String("redisserver", "tcp:127.0.0.1:6379", "redis server address (tcp:127.0.0.1:6379)")
|
||||
redisdb = flag.Int("rdb", 10, "redis database number (10)")
|
||||
redispass = flag.String("pass", "", "redis database password")
|
||||
flush = flag.Bool("flush", false, "Flush the database before importing")
|
||||
monthsFn = flag.String("month", "Months.csv", "Months file")
|
||||
monthdaysFn = flag.String("monthdays", "MonthDays.csv", "Month days file")
|
||||
weekdaysFn = flag.String("weekdays", "WeekDays.csv", "Week days file")
|
||||
destinationsFn = flag.String("destinations", "Destinations.csv", "Destinations file")
|
||||
ratesFn = flag.String("rates", "Rates.csv", "Rates file")
|
||||
timingsFn = flag.String("timings", "Timings.csv", "Timings file")
|
||||
ratestimingsFn = flag.String("ratestimings", "RatesTimings.csv", "Rates timings file")
|
||||
ratingprofilesFn = flag.String("ratingprofiles", "RatingProfiles.csv", "Rating profiles file")
|
||||
actionsFn = flag.String("actions", "Actions.csv", "Actions file")
|
||||
actionstimingsFn = flag.String("actionstimings", "ActionsTimings.csv", "Actions timings file")
|
||||
actionstriggersFn = flag.String("actionstriggers", "ActionsTriggers.csv", "Actions triggers file")
|
||||
accountactionsFn = flag.String("accountactions", "AccountActions.csv", "Account actions file")
|
||||
sep rune
|
||||
)
|
||||
|
||||
func writeToDatabase() {
|
||||
@@ -70,7 +72,9 @@ func main() {
|
||||
loadTimings()
|
||||
loadRatesTimings()
|
||||
loadRatingProfiles()
|
||||
loadPrimaryBalanceActions()
|
||||
loadDestinationBalanceActions()
|
||||
loadActions()
|
||||
loadActionsTimings()
|
||||
loadActionsTriggers()
|
||||
loadAccountActions()
|
||||
writeToDatabase()
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/cgrates/cgrates/timespans"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Rate struct {
|
||||
@@ -68,12 +69,15 @@ type Timing struct {
|
||||
}
|
||||
|
||||
func NewTiming(timeingInfo ...string) (rt *Timing) {
|
||||
rt = &Timing{
|
||||
StartTime: timeingInfo[3],
|
||||
}
|
||||
rt = &Timing{}
|
||||
rt.Months.Parse(timeingInfo[0], ";")
|
||||
rt.MonthDays.Parse(timeingInfo[1], ";")
|
||||
rt.WeekDays.Parse(timeingInfo[2], ";")
|
||||
if timeingInfo[3] == "*now" {
|
||||
rt.StartTime = time.Now().Format("00:00:00")
|
||||
} else {
|
||||
rt.StartTime = timeingInfo[3]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
3
data/AccountActions.csv
Normal file
3
data/AccountActions.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
Tenant,Account,Direction,ActionTimingsTag,ActionTriggersTag
|
||||
CUSTOMER_1,rif,OUT,STANDARD_ABO,STANDARD_TRIGGER
|
||||
CUSTOMER_1,dan,OUT,STANDARD_ABO,STANDARD_TRIGGER
|
||||
|
6
data/ActionTimings.csv
Normal file
6
data/ActionTimings.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
Tag,ActionsTag,TimingTag
|
||||
STANDARD_ABO,SOME,WEEKLY_SAME_TIME
|
||||
STANDARD_ABO,SOME,WEEKLY_SAME_TIME
|
||||
STANDARD_ABO,SOME,WEEKLY_SAME_TIME
|
||||
STANDARD_ABO,SOME,ONE_TIME_RUN
|
||||
STANDARD_ABO,SOME,FIRST_DAY_OF_MONTH
|
||||
|
5
data/ActionTriggers.csv
Normal file
5
data/ActionTriggers.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
ActionTag,BalanceTag,ThresholdValue,DestinationTag,ActionsTag
|
||||
STANDARD_TRIGGER,MONETARY,30,*all,SOME_1
|
||||
STANDARD_TRIGGER,SMS,30,*all,SOME_2
|
||||
STANDARD_TRIGGER,MINUTES,10,GERMANY_O2,SOME_1
|
||||
STANDARD_TRIGGER,MINUTES,200,GERMANY,SOME_2
|
||||
|
8
data/Actions.csv
Normal file
8
data/Actions.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
Tag,Action,BalanceTag,Units,DestinationTag,PriceType,PriceValue,Weight
|
||||
SOME,TOPUP_RESET,MONETARY,10,*all,,,
|
||||
SOME,TOPUP_RESET,SMS,100,*all,,,
|
||||
SOME,TOPUP_RESET,INTERNET,1000,*all,,,
|
||||
SOME,POSTPAID_RESET,MONETARY,10,*all,,,
|
||||
SOME,DEBIT,MONETARY,5,*all,,,
|
||||
SOME_1,DEBIT,MINUTES,10,GERMANY_O2,PERCENT,25,10
|
||||
SOME_2,TOPUP_RESET,MINUTES,1000,GERMANY,ABSOLUTE,0.2,10
|
||||
|
@@ -1,4 +0,0 @@
|
||||
TimingTag,Action,Tenant,Account,Direction,DestinationTag,Units,PriceType,PriceValue,Weight
|
||||
WEEKLY_SAME_TIME,TOPUP_RESET,CUSTOMER_1,rif,OUT,GERMANY,1000,PRECENT,10,10
|
||||
WEEKLY_SAME_TIME,TOPUP_RESET,CUSTOMER_1,rif,OUT,GERMANY_O2,100,ABSOLUTE,0,10
|
||||
TRIGGERED,TOPUP_ADD,CUSTOMER_1,rif,OUT,GERMANY_O2,50,THRESHOLD,300,10
|
||||
|
@@ -1,6 +0,0 @@
|
||||
TimingTag,Action,Tenant,Account,Direction,BalanceTag,Units
|
||||
WEEKLY_SAME_TIME,TOPUP_RESET,CUSTOMER_1,rif,OUT,MONETARY,10
|
||||
WEEKLY_SAME_TIME,TOPUP_RESET,CUSTOMER_1,rif,OUT,SMS,100
|
||||
WEEKLY_SAME_TIME,TOPUP_RESET,CUSTOMER_1,rif,OUT,INTERNET,1000
|
||||
ONE_TIME_RUN,POSTPAID_RESET,CUSTOMER_1,dan,OUT,MONETARY,10
|
||||
FIRST_DAY_OF_MONTH,DEBIT,CUSTOMER_1,dan,OUT,MONETARY,5
|
||||
|
@@ -1,9 +1,9 @@
|
||||
TimingTag,MonthsTag,MonthDaysTag,WeekDaysTag,StartTime
|
||||
WORKDAYS_00,ALL,ALL,WORKDAYS,00:00:00
|
||||
WORKDAYS_18,ALL,ALL,WORKDAYS,18:00:00
|
||||
WEEKENDS,ALL,ALL,WEEKENDS,00:00:00
|
||||
WEEKLY_SAME_TIME,ALL,ALL,MONDAY,*now
|
||||
FIRST_DAY_OF_MONTH,ALL,FIRST,ALL,00:00:00
|
||||
DAILY_SAME_TIME,ALL,ALL,ALL,*now
|
||||
ONE_TIME_RUN,NONE,NONE,NONE,*now
|
||||
TRIGGERED,NONE,NONE,NONE,*trigerred
|
||||
TimingTag,Months,MonthDays,WeekDays,StartTime
|
||||
WORKDAYS_00,*all,*all,*all,00:00:00
|
||||
WORKDAYS_18,*all,*all,*all,18:00:00
|
||||
WEEKENDS,*all,*all,6;7,00:00:00
|
||||
WEEKLY_SAME_TIME,*all,*all,1,*now
|
||||
FIRST_DAY_OF_MONTH,*all,1,*all,00:00:00
|
||||
DAILY_SAME_TIME,*all,*all,*all,*now
|
||||
ONE_TIME_RUN,*none,*none,*none,*now
|
||||
WINTER_FIRST_DAYS,1;2;12,1,*none,00:00:00
|
||||
|
BIN
data/test.kch
BIN
data/test.kch
Binary file not shown.
@@ -18,10 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
package timespans
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
)
|
||||
import ()
|
||||
|
||||
// Amount of a trafic of a certain type (TOR)
|
||||
type UnitsCounter struct {
|
||||
@@ -62,32 +59,18 @@ func (uc *UnitsCounter) getDestination() (dest *Destination) {
|
||||
Structure to be filled for each tariff plan with the bonus value for received calls minutes.
|
||||
*/
|
||||
type Action struct {
|
||||
Id string
|
||||
ActionType string
|
||||
Direction string
|
||||
TOR string
|
||||
Units float64
|
||||
balanceMap map[string]float64
|
||||
BalanceMap map[string]float64
|
||||
MinuteBuckets []*MinuteBucket
|
||||
Weight float64
|
||||
DestinationsId string
|
||||
destination *Destination
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (a *Action) store() (result string) {
|
||||
buf := new(bytes.Buffer)
|
||||
gob.NewEncoder(buf).Encode(a)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (a *Action) restore(input string) {
|
||||
gob.NewDecoder(bytes.NewBuffer([]byte(input))).Decode(a)
|
||||
}
|
||||
|
||||
// Structure to store actions according to weight
|
||||
type actionsorter []*Action
|
||||
|
||||
@@ -102,3 +85,18 @@ func (s actionsorter) Swap(i, j int) {
|
||||
func (s actionsorter) Less(j, i int) bool {
|
||||
return s[i].Weight < s[j].Weight
|
||||
}
|
||||
|
||||
type ActionTrigger struct {
|
||||
BalanceId string
|
||||
ThresholdValue float64
|
||||
DestinationId string
|
||||
destination *Destination
|
||||
ActionsId string
|
||||
actions []*Action
|
||||
}
|
||||
|
||||
type ActionTiming struct {
|
||||
Id string
|
||||
ActionsId string
|
||||
actions []*Action
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ package timespans
|
||||
import (
|
||||
"time"
|
||||
//"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -41,49 +39,3 @@ func (ap *ActivationPeriod) AddInterval(is ...*Interval) {
|
||||
ap.Intervals = append(ap.Intervals, i)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the activation periods for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (ap *ActivationPeriod) store() (result string) {
|
||||
result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + ";"
|
||||
for _, i := range ap.Intervals {
|
||||
var is string
|
||||
is = i.Months.store() + "|"
|
||||
is += i.MonthDays.store() + "|"
|
||||
is += i.WeekDays.store() + "|"
|
||||
is += i.StartTime + "|"
|
||||
is += i.EndTime + "|"
|
||||
is += strconv.FormatFloat(i.Weight, 'f', -1, 64) + "|"
|
||||
is += strconv.FormatFloat(i.ConnectFee, 'f', -1, 64) + "|"
|
||||
is += strconv.FormatFloat(i.Price, 'f', -1, 64) + "|"
|
||||
is += strconv.FormatFloat(i.BillingUnit, 'f', -1, 64)
|
||||
result += is + ";"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the activation periods for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (ap *ActivationPeriod) restore(input string) {
|
||||
elements := strings.Split(input, ";")
|
||||
unixNano, _ := strconv.ParseInt(elements[0], 10, 64)
|
||||
ap.ActivationTime = time.Unix(0, unixNano).In(time.UTC)
|
||||
ap.Intervals = make([]*Interval, 0)
|
||||
for _, is := range elements[1 : len(elements)-1] {
|
||||
i := &Interval{}
|
||||
ise := strings.Split(is, "|")
|
||||
i.Months.restore(ise[0])
|
||||
i.MonthDays.restore(ise[1])
|
||||
i.WeekDays.restore(ise[2])
|
||||
i.StartTime = ise[3]
|
||||
i.EndTime = ise[4]
|
||||
i.Weight, _ = strconv.ParseFloat(ise[5], 64)
|
||||
i.ConnectFee, _ = strconv.ParseFloat(ise[6], 64)
|
||||
i.Price, _ = strconv.ParseFloat(ise[7], 64)
|
||||
i.BillingUnit, _ = strconv.ParseFloat(ise[8], 64)
|
||||
|
||||
ap.Intervals = append(ap.Intervals, i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package timespans
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"encoding/json"
|
||||
"time"
|
||||
//"log"
|
||||
)
|
||||
@@ -30,16 +31,6 @@ func init() {
|
||||
SetStorageGetter(sg)
|
||||
}
|
||||
|
||||
func TestApRestoreKyoto(t *testing.T) {
|
||||
cd := &CallDescriptor{Tenant: "vdf",
|
||||
Subject: "rif",
|
||||
Destination: "0257"}
|
||||
cd.SearchStorageForPrefix()
|
||||
if len(cd.ActivationPeriods) != 2 {
|
||||
t.Error("Error restoring activation periods: ", cd.ActivationPeriods)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApRestoreRedis(t *testing.T) {
|
||||
cd := &CallDescriptor{Tenant: "vdf",
|
||||
Subject: "rif",
|
||||
@@ -59,13 +50,13 @@ func TestApStoreRestore(t *testing.T) {
|
||||
EndTime: "15:00:00"}
|
||||
ap := &ActivationPeriod{ActivationTime: d}
|
||||
ap.AddInterval(i)
|
||||
result := ap.store()
|
||||
expected := "1328106601000000000;2|1|3,4|14:30:00|15:00:00|0|0|0|0;"
|
||||
if result != expected {
|
||||
result, _ := json.Marshal(ap)
|
||||
expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Months\":[2],\"MonthDays\":[1],\"WeekDays\":[3,4],\"StartTime\":\"14:30:00\",\"EndTime\":\"15:00:00\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"BillingUnit\":0}]}"
|
||||
if string(result) != expected {
|
||||
t.Errorf("Expected %q was %q", expected, result)
|
||||
}
|
||||
ap1 := ActivationPeriod{}
|
||||
ap1.restore(result)
|
||||
json.Unmarshal(result, &ap1)
|
||||
if reflect.DeepEqual(ap, ap1) {
|
||||
t.Errorf("Expected %v was %v", ap, ap1)
|
||||
}
|
||||
@@ -76,22 +67,19 @@ func TestApStoreRestoreBlank(t *testing.T) {
|
||||
i := &Interval{}
|
||||
ap := &ActivationPeriod{ActivationTime: d}
|
||||
ap.AddInterval(i)
|
||||
result := ap.store()
|
||||
expected := "1328106601000000000;|||||0|0|0|0;"
|
||||
if result != expected {
|
||||
result, _ := json.Marshal(ap)
|
||||
expected := "{\"ActivationTime\":\"2012-02-01T14:30:01Z\",\"Intervals\":[{\"Months\":null,\"MonthDays\":null,\"WeekDays\":null,\"StartTime\":\"\",\"EndTime\":\"\",\"Weight\":0,\"ConnectFee\":0,\"Price\":0,\"BillingUnit\":0}]}"
|
||||
if string(result) != expected {
|
||||
t.Errorf("Expected %q was %q", expected, result)
|
||||
}
|
||||
ap1 := ActivationPeriod{}
|
||||
ap1.restore(result)
|
||||
json.Unmarshal(result, &ap1)
|
||||
if reflect.DeepEqual(ap, ap1) {
|
||||
t.Errorf("Expected %v was %v", ap, ap1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFallbackDirect(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0745"}
|
||||
cd.SearchStorageForPrefix()
|
||||
if len(cd.ActivationPeriods) != 1 {
|
||||
@@ -100,9 +88,6 @@ func TestFallbackDirect(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFallbackWithBackTrace(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0745121"}
|
||||
cd.SearchStorageForPrefix()
|
||||
if len(cd.ActivationPeriods) != 1 {
|
||||
@@ -111,9 +96,6 @@ func TestFallbackWithBackTrace(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFallbackDefault(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "00000"}
|
||||
cd.SearchStorageForPrefix()
|
||||
if len(cd.ActivationPeriods) != 1 {
|
||||
@@ -122,9 +104,6 @@ func TestFallbackDefault(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFallbackNoInfiniteLoop(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0721"}
|
||||
cd.SearchStorageForPrefix()
|
||||
if len(cd.ActivationPeriods) != 0 {
|
||||
@@ -137,7 +116,7 @@ func TestFallbackNoInfiniteLoop(t *testing.T) {
|
||||
func BenchmarkActivationPeriodRestore(b *testing.B) {
|
||||
ap := ActivationPeriod{}
|
||||
for i := 0; i < b.N; i++ {
|
||||
ap.restore("1328106601;2|1|3,4|14:30:00|15:00:00|0|0|0|0;")
|
||||
json.Unmarshal([]byte("1328106601;2|1|3,4|14:30:00|15:00:00|0|0|0|0;"), &ap)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +134,7 @@ func BenchmarkActivationPeriodStoreRestore(b *testing.B) {
|
||||
ap1 := ActivationPeriod{}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
result := ap.store()
|
||||
ap1.restore(result)
|
||||
result, _ := json.Marshal(ap)
|
||||
json.Unmarshal(result, &ap1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,6 @@ func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeS
|
||||
timespans = append(timespans, firstSpan)
|
||||
// split on (free) minute buckets
|
||||
if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
|
||||
userBalance.mux.RLock()
|
||||
_, bucketList := userBalance.getSecondsForPrefix(cd.Destination)
|
||||
for _, mb := range bucketList {
|
||||
for i := 0; i < len(timespans); i++ {
|
||||
@@ -180,7 +179,6 @@ func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeS
|
||||
}
|
||||
}
|
||||
}
|
||||
userBalance.mux.RUnlock()
|
||||
}
|
||||
if firstSpan.MinuteInfo != nil {
|
||||
return // all the timespans are on minutes
|
||||
@@ -285,10 +283,8 @@ func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) {
|
||||
if userBalance.Type == UB_TYPE_POSTPAID {
|
||||
return -1, nil
|
||||
} else {
|
||||
userBalance.mux.RLock()
|
||||
availableCredit = userBalance.BalanceMap[CREDIT]
|
||||
availableSeconds, _ = userBalance.getSecondsForPrefix(cd.Destination)
|
||||
userBalance.mux.RUnlock()
|
||||
}
|
||||
} else {
|
||||
return cd.Amount, err
|
||||
@@ -389,9 +385,9 @@ The amount filed has to be filled in call descriptor.
|
||||
/*
|
||||
Resets user balances value to the amounts specified in the tariff plan.
|
||||
*/
|
||||
func (cd *CallDescriptor) ResetUserBalance() (err error) {
|
||||
/*func (cd *CallDescriptor) ResetUserBalance() (err error) {
|
||||
if userBalance, err := cd.getUserBalance(); err == nil && userBalance != nil {
|
||||
return userBalance.resetUserBalance()
|
||||
}
|
||||
return err
|
||||
}
|
||||
}*/
|
||||
|
||||
@@ -80,26 +80,6 @@ func TestKyotoGetCost(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRedisGetCost(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{Tenant: "vdf", Subject: "rif", Destination: "0256", Cost: 540, ConnectFee: 0}
|
||||
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
|
||||
t.Errorf("Expected %v was %v", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMongoGetCost(t *testing.T) {
|
||||
getter, err := NewMongoStorage("127.0.0.1", "test")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
@@ -111,8 +91,6 @@ func TestMongoGetCost(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFullDestNotFound(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
@@ -126,9 +104,6 @@ func TestFullDestNotFound(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMultipleActivationPeriods(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 8, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
@@ -301,39 +276,8 @@ func BenchmarkRedisGetCost(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKyotoGetting(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewKyotoStorage("../data/test.kch")
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
key := cd.GetKey()
|
||||
getter.GetActivationPeriodsOrFallback(key)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKyotoRestoring(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewKyotoStorage("../data/test.kch")
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.SearchStorageForPrefix()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSplitting(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewKyotoStorage("../data/test.kch")
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
@@ -345,70 +289,6 @@ func BenchmarkSplitting(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKyotoGetCost(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewKyotoStorage("../data/test.kch")
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetCost()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMongoGetting(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.GetActivationPeriodsOrFallback(cd.GetKey())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMongoGetCost(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
|
||||
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "rif", Destination: "0256", TimeStart: t1, TimeEnd: t2}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetCost()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKyotoSingleGetSessionTime(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewKyotoStorage("../data/test.kch")
|
||||
defer getter.Close()
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "minutosu", Destination: "0723", Amount: 100}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetMaxSessionTime()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKyotoMultipleGetSessionTime(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewKyotoStorage("../data/test.kch")
|
||||
defer getter.Close()
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "minutosu", Destination: "0723", Amount: 5400}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetMaxSessionTime()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRedisSingleGetSessionTime(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewRedisStorage("", 10)
|
||||
@@ -430,25 +310,3 @@ func BenchmarkRedisMultipleGetSessionTime(b *testing.B) {
|
||||
cd.GetMaxSessionTime()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMongoSingleGetSessionTime(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "minutosu", Destination: "0723", Amount: 100}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetMaxSessionTime()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMongoMultipleGetSessionTime(b *testing.B) {
|
||||
b.StopTimer()
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
cd := &CallDescriptor{Tenant: "vdf", Subject: "minutosu", Destination: "0723", Amount: 5400}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetMaxSessionTime()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,30 +40,20 @@ func (m Months) Contains(month time.Month) (result bool) {
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the month for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (m Months) store() (result string) {
|
||||
for _, ms := range m {
|
||||
result += strconv.Itoa(int(ms)) + ","
|
||||
}
|
||||
result = strings.TrimRight(result, ",")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the month for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (m *Months) restore(input string) {
|
||||
m.Parse(input, ",")
|
||||
}
|
||||
|
||||
// Loades Month elemnents from a string separated by sep.
|
||||
func (m *Months) Parse(input, sep string) {
|
||||
elements := strings.Split(input, sep)
|
||||
for _, ms := range elements {
|
||||
if month, err := strconv.Atoi(ms); err == nil {
|
||||
*m = append(*m, time.Month(month))
|
||||
switch input {
|
||||
case "*all":
|
||||
*m = []time.Month{time.January, time.February, time.March, time.April, time.May, time.June,
|
||||
time.July, time.August, time.September, time.October, time.November, time.December}
|
||||
case "*none":
|
||||
*m = []time.Month{}
|
||||
default:
|
||||
elements := strings.Split(input, sep)
|
||||
for _, ms := range elements {
|
||||
if month, err := strconv.Atoi(ms); err == nil {
|
||||
*m = append(*m, time.Month(month))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,30 +73,19 @@ func (md MonthDays) Contains(monthDay int) (result bool) {
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the month days for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (md MonthDays) store() (result string) {
|
||||
for _, mds := range md {
|
||||
result += strconv.Itoa(mds) + ","
|
||||
}
|
||||
result = strings.TrimRight(result, ",")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the month days for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (md *MonthDays) restore(input string) {
|
||||
md.Parse(input, ",")
|
||||
}
|
||||
|
||||
// Parse MonthDay elements from string separated by sep.
|
||||
func (md *MonthDays) Parse(input, sep string) {
|
||||
elements := strings.Split(input, sep)
|
||||
for _, mds := range elements {
|
||||
if day, err := strconv.Atoi(mds); err == nil {
|
||||
*md = append(*md, day)
|
||||
switch input {
|
||||
case "*all":
|
||||
*md = []int{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}
|
||||
case "*none":
|
||||
*md = []int{}
|
||||
default:
|
||||
elements := strings.Split(input, sep)
|
||||
for _, mds := range elements {
|
||||
if day, err := strconv.Atoi(mds); err == nil {
|
||||
*md = append(*md, day)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,29 +105,18 @@ func (wd WeekDays) Contains(weekDay time.Weekday) (result bool) {
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the week days for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (wd WeekDays) store() (result string) {
|
||||
for _, wds := range wd {
|
||||
result += strconv.Itoa(int(wds)) + ","
|
||||
}
|
||||
result = strings.TrimRight(result, ",")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the week days for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (wd *WeekDays) restore(input string) {
|
||||
wd.Parse(input, ",")
|
||||
}
|
||||
|
||||
func (wd *WeekDays) Parse(input, sep string) {
|
||||
elements := strings.Split(input, sep)
|
||||
for _, wds := range elements {
|
||||
if day, err := strconv.Atoi(wds); err == nil {
|
||||
*wd = append(*wd, time.Weekday(day))
|
||||
switch input {
|
||||
case "*all":
|
||||
*wd = []time.Weekday{time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday, time.Saturday, time.Sunday}
|
||||
case "*none":
|
||||
*wd = []time.Weekday{}
|
||||
default:
|
||||
elements := strings.Split(input, sep)
|
||||
for _, wds := range elements {
|
||||
if day, err := strconv.Atoi(wds); err == nil {
|
||||
*wd = append(*wd, time.Weekday(day%7)) // %7 for sunday = 7 normalization
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,17 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func TestMonthStoreRestore(t *testing.T) {
|
||||
m := Months{5, 6, 7, 8}
|
||||
r := m.store()
|
||||
if r != "5,6,7,8," {
|
||||
r, _ := json.Marshal(m)
|
||||
if string(r) != "5,6,7,8," {
|
||||
t.Errorf("Error serializing months: %v", r)
|
||||
}
|
||||
o := Months{}
|
||||
o.restore(r)
|
||||
json.Unmarshal(r, &o)
|
||||
if !reflect.DeepEqual(o, m) {
|
||||
t.Errorf("Expected %v was %v", m, o)
|
||||
}
|
||||
@@ -39,12 +40,12 @@ func TestMonthStoreRestore(t *testing.T) {
|
||||
|
||||
func TestMonthDayStoreRestore(t *testing.T) {
|
||||
md := MonthDays{24, 25, 26}
|
||||
r := md.store()
|
||||
if r != "24,25,26," {
|
||||
r, _ := json.Marshal(md)
|
||||
if string(r) != "24,25,26," {
|
||||
t.Errorf("Error serializing month days: %v", r)
|
||||
}
|
||||
o := MonthDays{}
|
||||
o.restore(r)
|
||||
json.Unmarshal(r, &o)
|
||||
if !reflect.DeepEqual(o, md) {
|
||||
t.Errorf("Expected %v was %v", md, o)
|
||||
}
|
||||
@@ -52,12 +53,12 @@ func TestMonthDayStoreRestore(t *testing.T) {
|
||||
|
||||
func TestWeekDayStoreRestore(t *testing.T) {
|
||||
wd := WeekDays{time.Saturday, time.Sunday}
|
||||
r := wd.store()
|
||||
if r != "6,0," {
|
||||
r, _ := json.Marshal(wd)
|
||||
if string(r) != "6,0," {
|
||||
t.Errorf("Error serializing week days: %v", r)
|
||||
}
|
||||
o := WeekDays{}
|
||||
o.restore(r)
|
||||
json.Unmarshal(r, &o)
|
||||
if !reflect.DeepEqual(o, wd) {
|
||||
t.Errorf("Expected %v was %v", wd, o)
|
||||
}
|
||||
|
||||
@@ -18,10 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
package timespans
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
Structure that gathers multiple destination prefixes under a common id.
|
||||
*/
|
||||
@@ -30,21 +26,6 @@ type Destination struct {
|
||||
Prefixes []string
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the destination for the storage. Used for key-value storages.
|
||||
*/
|
||||
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, ",")
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the destination for the storage. Used for key-value storages.
|
||||
*/
|
||||
|
||||
@@ -21,60 +21,35 @@ package timespans
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func init() {
|
||||
sg, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
SetStorageGetter(sg)
|
||||
}
|
||||
|
||||
func TestDestinationStoreRestore(t *testing.T) {
|
||||
nationale := &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
s := nationale.store()
|
||||
s, _ := json.Marshal(nationale)
|
||||
d1 := &Destination{Id: "nat"}
|
||||
d1.restore(s)
|
||||
if d1.store() != s {
|
||||
t.Errorf("Expected %q was %q", s, d1.store())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestinationKyotoStore(t *testing.T) {
|
||||
getter, _ := NewKyotoStorage("../data/test.kch")
|
||||
defer getter.Close()
|
||||
nationale := &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
getter.SetDestination(nationale)
|
||||
result, _ := getter.GetDestination(nationale.Id)
|
||||
if !reflect.DeepEqual(nationale, result) {
|
||||
t.Errorf("Expected %q was %q", nationale, result)
|
||||
json.Unmarshal(s, d1)
|
||||
s1, _ := json.Marshal(d1)
|
||||
if reflect.DeepEqual(s1, s) {
|
||||
t.Errorf("Expected %q was %q", s, s1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestinationRedisStore(t *testing.T) {
|
||||
getter, err := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer getter.Close()
|
||||
nationale := &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
getter.SetDestination(nationale)
|
||||
result, _ := getter.GetDestination(nationale.Id)
|
||||
if !reflect.DeepEqual(nationale, result) {
|
||||
t.Errorf("Expected %q was %q", nationale, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestinationMongoStore(t *testing.T) {
|
||||
getter, err := NewMongoStorage("127.0.0.1", "test")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer getter.Close()
|
||||
nationale := &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
getter.SetDestination(nationale)
|
||||
result, _ := getter.GetDestination(nationale.Id)
|
||||
storageGetter.SetDestination(nationale)
|
||||
result, _ := storageGetter.GetDestination(nationale.Id)
|
||||
if !reflect.DeepEqual(nationale, result) {
|
||||
t.Errorf("Expected %q was %q", nationale, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDestinationContainsPrefix(t *testing.T) {
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
nationale := &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
contains, precision := nationale.containsPrefix("0256")
|
||||
if !contains || precision != len("0256") {
|
||||
@@ -85,32 +60,10 @@ func TestDestinationContainsPrefix(t *testing.T) {
|
||||
|
||||
/********************************* Benchmarks **********************************/
|
||||
|
||||
func BenchmarkDestinationKyotoStoreRestore(b *testing.B) {
|
||||
getter, _ := NewKyotoStorage("../data/test.kch")
|
||||
defer getter.Close()
|
||||
nationale := &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetDestination(nationale)
|
||||
getter.GetDestination(nationale.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDestinationRedisStoreRestore(b *testing.B) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
nationale := &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetDestination(nationale)
|
||||
getter.GetDestination(nationale.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDestinationMongoStoreRestore(b *testing.B) {
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
nationale := &Destination{Id: "nat", Prefixes: []string{"0257", "0256", "0723"}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetDestination(nationale)
|
||||
getter.GetDestination(nationale.Id)
|
||||
storageGetter.SetDestination(nationale)
|
||||
storageGetter.GetDestination(nationale.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ package timespans
|
||||
import (
|
||||
// "log"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MinuteBucket struct {
|
||||
@@ -35,28 +33,6 @@ type MinuteBucket struct {
|
||||
precision int
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the minute bucket for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (mb *MinuteBucket) store() (result string) {
|
||||
result += strconv.Itoa(int(mb.Seconds)) + "|"
|
||||
result += strconv.FormatFloat(mb.Weight, 'f', -1, 64) + "|"
|
||||
result += strconv.FormatFloat(mb.Price, '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, "|")
|
||||
mb.Seconds, _ = strconv.ParseFloat(elements[0], 64)
|
||||
mb.Weight, _ = strconv.ParseFloat(elements[1], 64)
|
||||
mb.Price, _ = strconv.ParseFloat(elements[2], 64)
|
||||
mb.DestinationId = elements[3]
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the destination loading it from the storage if necessary.
|
||||
*/
|
||||
|
||||
@@ -28,8 +28,8 @@ type StorageGetter interface {
|
||||
SetActivationPeriodsOrFallback(string, []*ActivationPeriod, string) error
|
||||
GetDestination(string) (*Destination, error)
|
||||
SetDestination(*Destination) error
|
||||
GetTariffPlan(string) (*TariffPlan, error)
|
||||
SetTariffPlan(*TariffPlan) error
|
||||
GetActions(string) ([]*Action, error)
|
||||
SetActions(string, []*Action) error
|
||||
GetUserBalance(string) (*UserBalance, error)
|
||||
SetUserBalance(*UserBalance) error
|
||||
}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carrieks World
|
||||
Copyright (C) 2012 Radu Ioan Fericean
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either veksion 3 of the License, or
|
||||
(at your option) any later veksion.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package timespans
|
||||
|
||||
import (
|
||||
//"github.com/fsouza/gokabinet/kc"
|
||||
"bitbucket.org/ww/cabinet"
|
||||
//"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type KyotoStorage struct {
|
||||
db *cabinet.KCDB
|
||||
}
|
||||
|
||||
func NewKyotoStorage(filaName string) (*KyotoStorage, error) {
|
||||
// ndb, err := kc.Open(filaName, kc.WRITE)
|
||||
ndb := cabinet.New()
|
||||
err := ndb.Open(filaName, cabinet.KCOWRITER|cabinet.KCOCREATE)
|
||||
return &KyotoStorage{db: ndb}, err
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) Close() {
|
||||
ks.db.Close()
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetActivationPeriodsOrFallback(key string) (aps []*ActivationPeriod, fallbackKey string, err error) {
|
||||
valuesBytes, err := ks.db.Get([]byte(key))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
valuesString := string(valuesBytes)
|
||||
values := strings.Split(valuesString, "\n")
|
||||
if len(values) > 1 {
|
||||
for _, ap_string := range values {
|
||||
if len(ap_string) > 0 {
|
||||
ap := &ActivationPeriod{}
|
||||
ap.restore(ap_string)
|
||||
aps = append(aps, ap)
|
||||
}
|
||||
}
|
||||
} else { // fallback case
|
||||
fallbackKey = valuesString
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) SetActivationPeriodsOrFallback(key string, aps []*ActivationPeriod, fallbackKey string) error {
|
||||
result := ""
|
||||
if len(aps) > 0 {
|
||||
for _, ap := range aps {
|
||||
result += ap.store() + "\n"
|
||||
}
|
||||
} else {
|
||||
result = fallbackKey
|
||||
}
|
||||
return ks.db.Set([]byte(key), []byte(result))
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetDestination(key string) (dest *Destination, err error) {
|
||||
if values, err := ks.db.Get([]byte(key)); err == nil {
|
||||
dest = &Destination{Id: key}
|
||||
dest.restore(string(values))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) SetDestination(dest *Destination) error {
|
||||
return ks.db.Set([]byte(dest.Id), []byte(dest.store()))
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetTariffPlan(key string) (tp *TariffPlan, err error) {
|
||||
if values, err := ks.db.Get([]byte(key)); err == nil {
|
||||
tp = &TariffPlan{Id: key}
|
||||
tp.restore(string(values))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) SetTariffPlan(tp *TariffPlan) error {
|
||||
return ks.db.Set([]byte(tp.Id), []byte(tp.store()))
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) GetUserBalance(key string) (ub *UserBalance, err error) {
|
||||
if values, err := ks.db.Get([]byte(key)); err == nil {
|
||||
ub = &UserBalance{Id: key}
|
||||
ub.restore(string(values))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ks *KyotoStorage) SetUserBalance(ub *UserBalance) error {
|
||||
return ks.db.Set([]byte(ub.Id), []byte(ub.store()))
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2012 Radu Ioan Fericean
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package timespans
|
||||
|
||||
import (
|
||||
"launchpad.net/mgo"
|
||||
"launchpad.net/mgo/bson"
|
||||
"log"
|
||||
)
|
||||
|
||||
type MongoStorage struct {
|
||||
db *mgo.Database
|
||||
session *mgo.Session
|
||||
}
|
||||
|
||||
func NewMongoStorage(address, db string) (*MongoStorage, error) {
|
||||
session, err := mgo.Dial(address)
|
||||
if err != nil {
|
||||
log.Print("Could not contact mongo server")
|
||||
return nil, err
|
||||
}
|
||||
session.SetMode(mgo.Monotonic, true)
|
||||
|
||||
index := mgo.Index{Key: []string{"key"}, Unique: true, DropDups: true, Background: true}
|
||||
err = session.DB(db).C("activationPeriods").EnsureIndex(index)
|
||||
index = mgo.Index{Key: []string{"id"}, Unique: true, DropDups: true, Background: true}
|
||||
err = session.DB(db).C("destinations").EnsureIndex(index)
|
||||
err = session.DB(db).C("tariffPlans").EnsureIndex(index)
|
||||
err = session.DB(db).C("userBalance").EnsureIndex(index)
|
||||
|
||||
return &MongoStorage{db: session.DB(db), session: session}, nil
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) Close() {
|
||||
ms.session.Close()
|
||||
}
|
||||
|
||||
/*
|
||||
Helper type for activation periods storage.
|
||||
*/
|
||||
type KeyValue struct {
|
||||
Key string
|
||||
FallbackKey string
|
||||
ActivationPeriods []*ActivationPeriod
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) GetActivationPeriodsOrFallback(key string) (aps []*ActivationPeriod, fallbackKey string, err error) {
|
||||
ndb := ms.db.C("activationPeriods")
|
||||
result := KeyValue{}
|
||||
err = ndb.Find(bson.M{"key": key}).One(&result)
|
||||
return result.ActivationPeriods, result.FallbackKey, err
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) SetActivationPeriodsOrFallback(key string, aps []*ActivationPeriod, fallbackKey string) error {
|
||||
ndb := ms.db.C("activationPeriods")
|
||||
return ndb.Insert(&KeyValue{key, fallbackKey, aps})
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) GetDestination(key string) (result *Destination, err error) {
|
||||
ndb := ms.db.C("destinations")
|
||||
result = &Destination{}
|
||||
err = ndb.Find(bson.M{"id": key}).One(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) SetDestination(dest *Destination) error {
|
||||
ndb := ms.db.C("destinations")
|
||||
return ndb.Insert(&dest)
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) GetTariffPlan(key string) (result *TariffPlan, err error) {
|
||||
ndb := ms.db.C("tariffPlans")
|
||||
result = &TariffPlan{}
|
||||
err = ndb.Find(bson.M{"id": key}).One(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) SetTariffPlan(tp *TariffPlan) error {
|
||||
ndb := ms.db.C("tariffPlans")
|
||||
return ndb.Insert(&tp)
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) GetUserBalance(key string) (result *UserBalance, err error) {
|
||||
ndb := ms.db.C("userBalance")
|
||||
result = &UserBalance{}
|
||||
err = ndb.Find(bson.M{"id": key}).One(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (ms *MongoStorage) SetUserBalance(ub *UserBalance) error {
|
||||
ndb := ms.db.C("userBalance")
|
||||
return ndb.Insert(&ub)
|
||||
}
|
||||
@@ -20,7 +20,7 @@ package timespans
|
||||
|
||||
import (
|
||||
"github.com/simonz05/godis"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type RedisStorage struct {
|
||||
@@ -47,31 +47,20 @@ func (rs *RedisStorage) GetActivationPeriodsOrFallback(key string) (aps []*Activ
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
valuesString := elem.String()
|
||||
values := strings.Split(valuesString, "\n")
|
||||
if len(values) > 1 {
|
||||
for _, ap_string := range values {
|
||||
if len(ap_string) > 0 {
|
||||
ap := &ActivationPeriod{}
|
||||
ap.restore(ap_string)
|
||||
aps = append(aps, ap)
|
||||
}
|
||||
}
|
||||
} else { // fallback case
|
||||
fallbackKey = valuesString
|
||||
err = json.Unmarshal(elem, &aps)
|
||||
if err != nil {
|
||||
err = json.Unmarshal(elem, &fallbackKey)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) SetActivationPeriodsOrFallback(key string, aps []*ActivationPeriod, fallbackKey string) error {
|
||||
func (rs *RedisStorage) SetActivationPeriodsOrFallback(key string, aps []*ActivationPeriod, fallbackKey string) (err error) {
|
||||
//.db.Select(rs.dbNb)
|
||||
result := ""
|
||||
var result []byte
|
||||
if len(aps) > 0 {
|
||||
for _, ap := range aps {
|
||||
result += ap.store() + "\n"
|
||||
}
|
||||
result, err = json.Marshal(aps)
|
||||
} else {
|
||||
result = fallbackKey
|
||||
result, err = json.Marshal(fallbackKey)
|
||||
}
|
||||
return rs.db.Set(key, result)
|
||||
}
|
||||
@@ -80,39 +69,41 @@ func (rs *RedisStorage) GetDestination(key string) (dest *Destination, err error
|
||||
//rs.db.Select(rs.dbNb + 1)
|
||||
if values, err := rs.db.Get(key); err == nil {
|
||||
dest = &Destination{Id: key}
|
||||
dest.restore(values.String())
|
||||
err = json.Unmarshal(values, dest)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (rs *RedisStorage) SetDestination(dest *Destination) error {
|
||||
func (rs *RedisStorage) SetDestination(dest *Destination) (err error) {
|
||||
//rs.db.Select(rs.dbNb + 1)
|
||||
return rs.db.Set(dest.Id, dest.store())
|
||||
result, err := json.Marshal(dest)
|
||||
return rs.db.Set(dest.Id, result)
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) GetTariffPlan(key string) (tp *TariffPlan, err error) {
|
||||
func (rs *RedisStorage) GetActions(key string) (as []*Action, err error) {
|
||||
//rs.db.Select(rs.dbNb + 2)
|
||||
if values, err := rs.db.Get(key); err == nil {
|
||||
tp = &TariffPlan{Id: key}
|
||||
tp.restore(values.String())
|
||||
err = json.Unmarshal(values, as)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) SetTariffPlan(tp *TariffPlan) error {
|
||||
func (rs *RedisStorage) SetActions(key string, as []*Action) (err error) {
|
||||
//rs.db.Select(rs.dbNb + 2)
|
||||
return rs.db.Set(tp.Id, tp.store())
|
||||
result, err := json.Marshal(as)
|
||||
return rs.db.Set(key, result)
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) GetUserBalance(key string) (ub *UserBalance, err error) {
|
||||
//rs.db.Select(rs.dbNb + 3)
|
||||
if values, err := rs.db.Get(key); err == nil {
|
||||
ub = &UserBalance{Id: key}
|
||||
ub.restore(values.String())
|
||||
err = json.Unmarshal(values, ub)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *RedisStorage) SetUserBalance(ub *UserBalance) error {
|
||||
func (rs *RedisStorage) SetUserBalance(ub *UserBalance) (err error) {
|
||||
//rs.db.Select(rs.dbNb + 3)
|
||||
return rs.db.Set(ub.Id, ub.store())
|
||||
result, err := json.Marshal(ub)
|
||||
return rs.db.Set(ub.Id, result)
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2012 Radu Ioan Fericean
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package timespans
|
||||
|
||||
import (
|
||||
// "log"
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
)
|
||||
|
||||
const (
|
||||
// Direction type
|
||||
INBOUND = "IN"
|
||||
OUTBOUND = "OUT"
|
||||
// Balance types
|
||||
CREDIT = "MONETARY"
|
||||
SMS = "SMS"
|
||||
TRAFFIC = "INTERNET"
|
||||
)
|
||||
|
||||
/*
|
||||
Structure describing a tariff plan's number of bonus items. It is uset to restore
|
||||
these numbers to the user balance every month.
|
||||
*/
|
||||
type TariffPlan struct {
|
||||
Id string
|
||||
BalanceMap map[string]float64
|
||||
Actions []*Action
|
||||
MinuteBuckets []*MinuteBucket
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (tp *TariffPlan) store() (result string) {
|
||||
buf := new(bytes.Buffer)
|
||||
gob.NewEncoder(buf).Encode(tp)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the tariff plan for the storage. Used for key-value storages.
|
||||
*/
|
||||
func (tp *TariffPlan) restore(input string) {
|
||||
gob.NewDecoder(bytes.NewBuffer([]byte(input))).Decode(tp)
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
Rating system designed to be used in VoIP Carriers World
|
||||
Copyright (C) 2012 Radu Ioan Fericean
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package timespans
|
||||
|
||||
import (
|
||||
// "log"
|
||||
//"reflect"
|
||||
//"testing"
|
||||
)
|
||||
|
||||
/*func TestTariffPlanStoreRestore(t *testing.T) {
|
||||
b1 := &MinuteBucket{Seconds: 10, Weight: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Weight: 20, Price: 0.0, DestinationId: "retea"}
|
||||
rcb := &RecivedCallBonus{}
|
||||
vd := &VolumeDiscount{100, 10}
|
||||
seara := &TariffPlan{Id: "seara_voo",
|
||||
SmsCredit: 100,
|
||||
ReceivedCallSecondsLimit: 0,
|
||||
RecivedCallBonus: rcb,
|
||||
MinuteBuckets: []*MinuteBucket{b1, b2},
|
||||
VolumeDiscountThresholds: []*VolumeDiscount{vd}}
|
||||
s := seara.store()
|
||||
tp1 := &TariffPlan{Id: "seara_voo"}
|
||||
tp1.restore(s)
|
||||
if tp1.store() != s {
|
||||
t.Errorf("Expected %q was %q", s, tp1.store())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTariffPlanKyotoStore(t *testing.T) {
|
||||
getter, _ := NewKyotoStorage("../data/test.kch")
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Weight: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Weight: 20, Price: 0.0, DestinationId: "retea"}
|
||||
vd := &VolumeDiscount{100, 10}
|
||||
seara := &TariffPlan{Id: "seara_voo", SmsCredit: 100, ReceivedCallSecondsLimit: 0,
|
||||
MinuteBuckets: []*MinuteBucket{b1, b2}, VolumeDiscountThresholds: []*VolumeDiscount{vd}}
|
||||
getter.SetTariffPlan(seara)
|
||||
result, _ := getter.GetTariffPlan(seara.Id)
|
||||
if !reflect.DeepEqual(seara, result) {
|
||||
t.Errorf("Expected %q was %q", seara, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTariffPlanRedisStore(t *testing.T) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Weight: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Weight: 20, Price: 0.0, DestinationId: "retea"}
|
||||
vd := &VolumeDiscount{100, 10}
|
||||
seara := &TariffPlan{Id: "seara_voo", SmsCredit: 100, ReceivedCallSecondsLimit: 0,
|
||||
MinuteBuckets: []*MinuteBucket{b1, b2}, VolumeDiscountThresholds: []*VolumeDiscount{vd}}
|
||||
getter.SetTariffPlan(seara)
|
||||
result, _ := getter.GetTariffPlan(seara.Id)
|
||||
if !reflect.DeepEqual(seara, result) {
|
||||
t.Errorf("Expected %q was %q", seara, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTariffPlanMongoStore(t *testing.T) {
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Weight: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Weight: 20, Price: 0.0, DestinationId: "retea"}
|
||||
vd := &VolumeDiscount{100, 10}
|
||||
seara := &TariffPlan{Id: "seara_voo", SmsCredit: 100, ReceivedCallSecondsLimit: 0,
|
||||
MinuteBuckets: []*MinuteBucket{b1, b2}, VolumeDiscountThresholds: []*VolumeDiscount{vd}}
|
||||
getter.SetTariffPlan(seara)
|
||||
result, _ := getter.GetTariffPlan(seara.Id)
|
||||
if !reflect.DeepEqual(seara, result) {
|
||||
t.Log(seara)
|
||||
t.Log(result)
|
||||
t.Errorf("Expected %v was %v", seara.VolumeDiscountThresholds, result.VolumeDiscountThresholds)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/********************************* Benchmarks **********************************/
|
||||
|
||||
/*func BenchmarkTariffPlanKyotoStoreRestore(b *testing.B) {
|
||||
b1 := &MinuteBucket{Seconds: 10, Weight: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Weight: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara_other", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetTariffPlan(seara)
|
||||
getter.GetTariffPlan(seara.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTariffPlanRedisStoreRestore(b *testing.B) {
|
||||
getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Weight: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Weight: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara_other", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetTariffPlan(seara)
|
||||
getter.GetTariffPlan(seara.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTariffPlanMongoStoreRestore(b *testing.B) {
|
||||
getter, _ := NewMongoStorage("127.0.0.1", "test")
|
||||
defer getter.Close()
|
||||
b1 := &MinuteBucket{Seconds: 10, Weight: 10, Price: 0.01, DestinationId: "nationale"}
|
||||
b2 := &MinuteBucket{Seconds: 100, Weight: 20, Price: 0.0, DestinationId: "retea"}
|
||||
seara := &TariffPlan{Id: "seara_other", SmsCredit: 100, MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
for i := 0; i < b.N; i++ {
|
||||
getter.SetTariffPlan(seara)
|
||||
getter.GetTariffPlan(seara.Id)
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -21,14 +21,18 @@ package timespans
|
||||
import (
|
||||
// "log"
|
||||
"sort"
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
UB_TYPE_POSTPAID = "postpaid"
|
||||
UB_TYPE_PREPAID = "prepaid"
|
||||
// Direction type
|
||||
INBOUND = "IN"
|
||||
OUTBOUND = "OUT"
|
||||
// Balance types
|
||||
CREDIT = "MONETARY"
|
||||
SMS = "SMS"
|
||||
TRAFFIC = "INTERNET"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -39,14 +43,13 @@ var (
|
||||
Structure containing information about user's credit (minutes, cents, sms...).'
|
||||
*/
|
||||
type UserBalance struct {
|
||||
Id string
|
||||
Type string // prepaid-postpaid
|
||||
BalanceMap map[string]float64
|
||||
UnitsCounters []*UnitsCounter
|
||||
TariffPlanId string
|
||||
tariffPlan *TariffPlan
|
||||
MinuteBuckets []*MinuteBucket
|
||||
mux sync.RWMutex
|
||||
Id string
|
||||
Type string // prepaid-postpaid
|
||||
BalanceMap map[string]float64
|
||||
MinuteBuckets []*MinuteBucket
|
||||
InUnitsCounters []*UnitsCounter
|
||||
OutUnitsCounters []*UnitsCounter
|
||||
ActionTriggers []*ActionTrigger
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -77,32 +80,6 @@ func (bs bucketsorter) Less(j, i int) bool {
|
||||
bs[i].Price > bs[j].Price
|
||||
}
|
||||
|
||||
/*
|
||||
Serializes the user balance for the storage. Used for key-value storage.
|
||||
*/
|
||||
func (ub *UserBalance) store() (result string) {
|
||||
buf := new(bytes.Buffer)
|
||||
gob.NewEncoder(buf).Encode(ub)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
/*
|
||||
De-serializes the user balance for the storage. Used for key-value storage.
|
||||
*/
|
||||
func (ub *UserBalance) restore(input string) {
|
||||
gob.NewDecoder(bytes.NewBuffer([]byte(input))).Decode(ub)
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the tariff plan loading it from the storage if necessary.
|
||||
*/
|
||||
func (ub *UserBalance) getTariffPlan() (tp *TariffPlan, err error) {
|
||||
if ub.tariffPlan == nil && ub.TariffPlanId != "" {
|
||||
ub.tariffPlan, err = storageGetter.GetTariffPlan(ub.TariffPlanId)
|
||||
}
|
||||
return ub.tariffPlan, err
|
||||
}
|
||||
|
||||
/*
|
||||
Returns user's available minutes for the specified destination
|
||||
*/
|
||||
@@ -138,8 +115,6 @@ func (ub *UserBalance) getSecondsForPrefix(prefix string) (seconds float64, buck
|
||||
Debits some amount of user's money credit. Returns the remaining credit in user's balance.
|
||||
*/
|
||||
func (ub *UserBalance) debitMoneyBalance(amount float64) float64 {
|
||||
ub.mux.Lock()
|
||||
defer ub.mux.Unlock()
|
||||
ub.BalanceMap[CREDIT] -= amount
|
||||
storageGetter.SetUserBalance(ub)
|
||||
return ub.BalanceMap[CREDIT]
|
||||
@@ -152,8 +127,6 @@ If the amount is bigger than the sum of all seconds in the minute buckets than n
|
||||
debited and an error will be returned.
|
||||
*/
|
||||
func (ub *UserBalance) debitMinutesBalance(amount float64, prefix string) error {
|
||||
ub.mux.Lock()
|
||||
defer ub.mux.Unlock()
|
||||
avaliableNbSeconds, bucketList := ub.getSecondsForPrefix(prefix)
|
||||
if avaliableNbSeconds < amount {
|
||||
return new(AmountTooBig)
|
||||
@@ -199,8 +172,6 @@ Debits some amount of user's SMS balance. Returns the remaining SMS in user's ba
|
||||
If the amount is bigger than the balance than nothing wil be debited and an error will be returned
|
||||
*/
|
||||
func (ub *UserBalance) debitSMSBuget(amount float64) (float64, error) {
|
||||
ub.mux.Lock()
|
||||
defer ub.mux.Unlock()
|
||||
if ub.BalanceMap[SMS] < amount {
|
||||
return ub.BalanceMap[SMS], new(AmountTooBig)
|
||||
}
|
||||
@@ -214,8 +185,6 @@ func (ub *UserBalance) debitSMSBuget(amount float64) (float64, error) {
|
||||
Adds the specified amount of seconds.
|
||||
*/
|
||||
// func (ub *UserBalance) addReceivedCallSeconds(direction, tor, destination string, amount float64) error {
|
||||
// ub.mux.Lock()
|
||||
// defer ub.mux.Unlock()
|
||||
// ub.ReceivedCallSeconds += amount
|
||||
// if tariffPlan, err := ub.getTariffPlan(); tariffPlan != nil && err == nil {
|
||||
// if ub.ReceivedCallSeconds >= tariffPlan.ReceivedCallSecondsLimit {
|
||||
@@ -240,10 +209,8 @@ Adds the specified amount of seconds.
|
||||
/*
|
||||
Resets the user balance items to their tariff plan values.
|
||||
*/
|
||||
func (ub *UserBalance) resetUserBalance() (err error) {
|
||||
ub.mux.Lock()
|
||||
defer ub.mux.Unlock()
|
||||
if tp, err := ub.getTariffPlan(); err == nil {
|
||||
/*func (ub *UserBalance) resetUserBalance() (err error) {
|
||||
if tp, err := ub.getAccountActions(); err == nil {
|
||||
for k, _ := range ub.BalanceMap {
|
||||
ub.BalanceMap[k] = tp.BalanceMap[k]
|
||||
}
|
||||
@@ -259,3 +226,4 @@ func (ub *UserBalance) resetUserBalance() (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user